将二进制文件数据存入结构体数组时程序崩溃的技术求助
Let's Fix Your C Code for Reading Data into a Struct Array
Let’s break down the issues in your code that are causing crashes and unexpected behavior, then walk through the correct solutions for both binary and text file scenarios (since it’s unclear which format your accounts.dat uses).
Key Issues in Your Original Code
- Wrong tool for binary files:
fgets()is designed for text files, not binary. Binary files can contain null bytes or non-newline separators that will breakfgets()andstrtok(), leading to memory errors. - Zero-length buffer:
char string[0];has no storage space at all. Writing to it withfgets()causes immediate memory overwriting—this is almost certainly why your program crashes when assigning to the struct. - Variable name typo: You opened the file with
file_accountsbut tried to closeficheiro_contas—this will cause compilation errors or undefined behavior. - Unsafe string handling: Assigning directly with
atoi(item)without checking ifstrtok()returned a valid pointer, and not ensuring strings fit in your struct’s char arrays, risks more crashes.
Solution 1: If accounts.dat is a Binary File (Written with fwrite())
If you originally saved the struct array to the file using fwrite(), you can read it back directly with fread()—no parsing needed. This is the most efficient way for binary data:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #define MAX_ACCOUNTS 5 #define COUNTER 0 typedef struct t_account { int id; char name[50]; char provider[40]; char org[40]; char domain[50]; float balance; } t_account; int main() { t_account account[MAX_ACCOUNTS]; FILE *file_accounts; int read_count; int i = COUNTER; // Open binary file in read mode file_accounts = fopen("../accounts.dat", "rb"); if (file_accounts == NULL) { printf("Error, %s\n", strerror(errno)); exit(1); } printf("Reading binary account data:\n\n"); // Read entire struct array in one call (returns number of structs read) read_count = fread(account, sizeof(t_account), MAX_ACCOUNTS, file_accounts); // Print and verify the data for (; i < read_count; i++) { printf("Account #%d\n", i + 1); printf("ID: %d\n", account[i].id); printf("Name: %s\n", account[i].name); printf("Provider: %s\n", account[i].provider); printf("ORG: %s\n", account[i].org); printf("Domain: %s\n", account[i].domain); printf("Balance: %.2f Eur\n\n", account[i].balance); } fclose(file_accounts); return 0; }
Solution 2: If accounts.dat is a Text File (Semicolon-Separated)
If your file is plain text with fields separated by ;, fix the buffer size, use safe string copying, and add error checks for strtok():
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define MAX_ACCOUNTS 5 #define COUNTER 0 #define BUFFER_SIZE 256 // Large enough for one line of account data typedef struct t_account { int id; char name[50]; char provider[40]; char org[40]; char domain[50]; float balance; } t_account; int main() { t_account account[MAX_ACCOUNTS]; FILE *file_accounts; char string[BUFFER_SIZE]; int i = COUNTER; char *item; // Open text file (use "r" instead of "rb") file_accounts = fopen("../accounts.dat", "r"); if (file_accounts == NULL) { printf("Error, %s\n", strerror(errno)); exit(1); } printf("Reading text account data:\n\n"); // Read line by line, stop if we hit EOF or max accounts while (fgets(string, BUFFER_SIZE, file_accounts) != NULL && i < MAX_ACCOUNTS) { // Remove trailing newline (if present) string[strcspn(string, "\n")] = '\0'; // Parse each field with strtok, add checks to avoid crashes item = strtok(string, ";"); if (!item) break; account[i].id = strtol(item, NULL, 10); item = strtok(NULL, ";"); if (!item) break; // Use strncpy to avoid overflow, ensure null termination strncpy(account[i].name, item, sizeof(account[i].name) - 1); account[i].name[sizeof(account[i].name) - 1] = '\0'; item = strtok(NULL, ";"); if (!item) break; strncpy(account[i].provider, item, sizeof(account[i].provider) - 1); account[i].provider[sizeof(account[i].provider) - 1] = '\0'; item = strtok(NULL, ";"); if (!item) break; strncpy(account[i].org, item, sizeof(account[i].org) - 1); account[i].org[sizeof(account[i].org) - 1] = '\0'; item = strtok(NULL, ";"); if (!item) break; strncpy(account[i].domain, item, sizeof(account[i].domain) - 1); account[i].domain[sizeof(account[i].domain) - 1] = '\0'; item = strtok(NULL, ";"); if (!item) break; account[i].balance = strtof(item, NULL); // Print the parsed data printf("Account #%d\n", i + 1); printf("ID: %d\n", account[i].id); printf("Name: %s\n", account[i].name); printf("Provider: %s\n", account[i].provider); printf("ORG: %s\n", account[i].org); printf("Domain: %s\n", account[i].domain); printf("Balance: %.2f Eur\n\n", account[i].balance); i++; } fclose(file_accounts); return 0; }
Critical Fixes Explained
- Buffer size:
BUFFER_SIZEensures we have enough space to hold a full line of text without overflow. - Safe string copying:
strncpy()prevents writing past the bounds of your struct’s char arrays, and we manually add a null terminator to guarantee valid strings. - Error checks: We verify each
strtok()return value to avoid trying to parse a null pointer if the file format is broken. - Correct file modes: Use
"rb"for binary files and"r"for text files to ensure the OS handles line endings and binary data correctly.
内容的提问来源于stack exchange,提问作者João Neves
相关产品推荐
相关产品推荐

