You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将二进制文件数据存入结构体数组时程序崩溃的技术求助

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

  1. 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 break fgets() and strtok(), leading to memory errors.
  2. Zero-length buffer: char string[0]; has no storage space at all. Writing to it with fgets() causes immediate memory overwriting—this is almost certainly why your program crashes when assigning to the struct.
  3. Variable name typo: You opened the file with file_accounts but tried to close ficheiro_contas—this will cause compilation errors or undefined behavior.
  4. Unsafe string handling: Assigning directly with atoi(item) without checking if strtok() 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_SIZE ensures 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 09:58:11