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

使用fscanf读取银行客户文件至结构体数组仅首个数据生效,求解决

解决银行客户数据文件读取失败的问题

问题根源分析

你的代码存在多个关键错误,导致仅能读取首个客户数据:

  • 错误的循环条件:while(!feof(fptr))是典型误区,feof仅在读取操作尝试越过文件末尾后才会返回true,会导致循环多执行一次且无法正确识别读取失败。
  • 取地址符遗漏:读取balance时,fscanf("%f", customer[acc_count].balance)缺少&,%f要求传入float指针,直接传变量会触发内存访问错误。
  • 数组索引错误:读取贷款金额时使用loan[acc_count],acc_count是客户计数器,会超出loan数组的索引范围(0-2),应改为loan[1]。
  • 贷款原因读取逻辑错误:fscanf("%s")仅能读取单个空格分隔的字符串,无法读取整行贷款原因;且参数传递错误,%s不能同时对应三个字符串参数。此外,前序fscanf会在缓冲区留下换行符,导致后续fgets读取空行。
  • 未处理客户间空行:文件中每个客户数据后存在空行,原代码未处理,导致下一次读取姓名时读到空行,后续数据全部错位。
  • 空指针非法操作:读模式打开失败时,fptr为NULL,此时调用fclose(fptr)属于未定义行为。

修正后的代码

#include <stdio.h>
#include <string.h>

#define MAX_ACCOUNTS 100 // 根据实际需求调整最大值

struct bankInfo{
    char name[50];
    int pin;
    float balance;
    int loan[3];
    int loan_Total;
    int loan_count;
    char loan_reason[3][1000];
    float creditScore;
}customer[MAX_ACCOUNTS], closed_customers[MAX_ACCOUNTS];

int main() {
    FILE *fptr;
    char str[100];
    int acc_count = 0;
    char dummy_buf[100]; // 用于清理缓冲区换行符和空行

    fptr = fopen("BankManagement.txt", "r");
    if(fptr == NULL){
        // 读模式失败则创建新文件
        fptr = fopen("BankManagement.txt", "w");
        if(fptr == NULL){
            printf("无法创建文件\n");
            return 1;
        }
        fclose(fptr);
        return 0;
    }

    // 以读取姓名作为循环终止条件,直接判断读取是否成功
    while(fgets(str, 100, fptr) != NULL){
        // 跳过客户间的空行
        if(strlen(str) <= 1){
            continue;
        }
        // 去除换行符
        str[strcspn(str, "\n")] = '\0';
        strcpy(customer[acc_count].name, str);

        // 读取PIN,校验读取结果
        if(fscanf(fptr, "%d", &customer[acc_count].pin) != 1) break;
        // 读取余额,修复取地址符问题
        if(fscanf(fptr, "%f", &customer[acc_count].balance) != 1) break;
        // 读取3项贷款金额,修正索引错误
        if(fscanf(fptr, "%d %d %d", &customer[acc_count].loan[0], 
                  &customer[acc_count].loan[1], &customer[acc_count].loan[2]) != 3) break;
        // 读取贷款次数
        if(fscanf(fptr, "%d", &customer[acc_count].loan_count) != 1) break;

        // 清理fscanf留下的换行符,避免干扰后续fgets
        fgets(dummy_buf, 100, fptr);
        // 读取整行贷款原因
        if(fgets(str, 100, fptr) == NULL) break;
        str[strcspn(str, "\n")] = '\0';
        // 拆分贷款原因到数组
        char *token = strtok(str, " ");
        int i = 0;
        while(token != NULL && i < 3){
            strcpy(customer[acc_count].loan_reason[i], token);
            token = strtok(NULL, " ");
            i++;
        }
        // 无贷款时填充"0"
        while(i < 3){
            strcpy(customer[acc_count].loan_reason[i], "0");
            i++;
        }

        // 读取贷款总额
        if(fscanf(fptr, "%d", &customer[acc_count].loan_Total) != 1) break;
        // 读取信用分
        if(fscanf(fptr, "%f", &customer[acc_count].creditScore) != 1) break;

        // 清理当前客户数据后的换行符,准备读取下一个客户
        fgets(dummy_buf, 100, fptr);

        acc_count++;
        // 防止数组越界
        if(acc_count >= MAX_ACCOUNTS){
            printf("客户数量已达上限\n");
            break;
        }
    }
    fclose(fptr);

    // 测试输出读取结果
    for(int i=0; i<acc_count; i++){
        printf("客户%d:\n", i+1);
        printf("姓名:%s\n", customer[i].name);
        printf("PIN:%d\n", customer[i].pin);
        printf("余额:%.1f\n", customer[i].balance);
        printf("贷款金额:%d %d %d\n", customer[i].loan[0], customer[i].loan[1], customer[i].loan[2]);
        printf("贷款次数:%d\n", customer[i].loan_count);
        printf("贷款原因:%s %s %s\n", customer[i].loan_reason[0], customer[i].loan_reason[1], customer[i].loan_reason[2]);
        printf("贷款总额:%d\n", customer[i].loan_Total);
        printf("信用分:%.1f\n\n", customer[i].creditScore);
    }

    return 0;
}

核心修正点说明

  1. 用while(fgets(str, 100, fptr) != NULL)作为循环条件,直接判断姓名读取是否成功,同时跳过空行。
  2. 修复了balance读取时的取地址符问题,以及贷款金额数组的索引错误。
  3. 改用fgets读取整行贷款原因,再用strtok拆分到对应数组元素,处理无贷款时的填充逻辑。
  4. 每次fscanf后清理缓冲区换行符,避免干扰后续读取操作。
  5. 添加数组越界检查,防止超出MAX_ACCOUNTS限制。
  6. 移除空指针的fclose调用,添加文件创建失败的错误处理。

内容的提问来源于stack exchange,提问作者Kookaburra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:35:34