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

C语言中如何逐行读取文件每行的两个字符串并存储到结构体数组

嘿,我来帮你梳理下问题所在,你的代码里有几个关键问题导致了警告和运行异常,咱们一步步来解决:

问题分析与解决方案

核心问题拆解

1. fscanf_s的安全参数缺失

微软的fscanf_s是fscanf的安全增强版本,对于%s格式符,必须额外传入缓冲区的大小作为参数,用来防止缓冲区溢出。你之前的调用只传了缓冲区指针,没有传大小,这就是警告C4477和C4473的根源。

正确的调用逻辑需要为每个%s对应添加缓冲区长度参数,比如:

fscanf_s(fp1, "%s %s", 目标缓冲区, 缓冲区大小, 第二个目标缓冲区, 第二个缓冲区大小);

2. 循环逻辑完全混乱

你在while循环里面嵌套了for循环,还错误地使用了scanf_s(从标准输入读,不是文件),这会导致程序逻辑完全偏离预期:

  • 应该直接用fscanf_s从文件流fp1读取数据,每次读取一组后索引i自增,直到文件结束。
  • 变量i在使用前没有初始化,会导致未定义行为(比如从垃圾索引开始写入数组)。

3. 结构体字段长度不足

你的group字段定义为char group[1],但实际要存储的是单个字符(比如'A'、'B')加上字符串结束符\0,至少需要2个字节的空间,否则会导致缓冲区溢出,引发未知错误。

修正后的完整代码

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include <math.h>
#include "string.h"

struct StringStruct {
    char Stringname[16];
    char group[2];  // 扩容到2字节,容纳字符+结束符
} String[100];

#define MaxNumLines 100  // 用宏定义常量更规范

int main() {
    FILE *fp1;
    errno_t string_file = fopen_s(&fp1, "String.dat", "r");
    
    if (fp1 == NULL) {
        printf_s("Error: String.dat not found\n");
        exit(EXIT_FAILURE);  // 使用标准退出码更清晰
    }
    printf_s("File String.dat opened successfully\n");

    int i = 0;  // 初始化索引变量,避免未定义行为
    // 循环读取文件:限制最大行数,且仅当成功读取2个数据时继续
    while (i < MaxNumLines && fscanf_s(fp1, "%s %s", 
           String[i].Stringname, (unsigned int)sizeof(String[i].Stringname),
           String[i].group, (unsigned int)sizeof(String[i].group)) == 2) {
        i++;  // 每成功读取一组数据,索引自增
    }

    // 仅打印实际读取到的有效数据,避免输出未初始化的垃圾值
    for (int j = 0; j < i; j++) {
        printf_s("%-12s %s\n", String[j].Stringname, String[j].group);
    }

    fclose(fp1);  // 别忘了关闭文件,避免资源泄漏
    return 0;
}

关键改动说明

  • 修复fscanf_s的参数:为每个%s添加了对应的缓冲区大小参数,符合安全函数的要求。
  • 重构读取逻辑:初始化索引i,用while循环逐组读取文件数据,同时限制最大行数避免数组越界。
  • 扩容group字段:从1字节改为2字节,确保能容纳字符和结束符,避免缓冲区溢出。
  • 添加文件关闭操作:之前的代码未关闭文件,会导致系统资源泄漏。
  • 优化打印逻辑:只遍历实际读取到的行数,避免打印未初始化的垃圾数据。

额外优化提示

如果你只想读取单个字符作为group(比如'A'),可以把格式符改成%c,同时跳过换行符等空白字符:

// 修改结构体字段
char group;

// 读取时的格式串(前面加空格跳过空白)
fscanf_s(fp1, "%s %c", String[i].Stringname, (unsigned int)sizeof(String[i].Stringname), &String[i].group);

这样就不需要给group分配数组空间,逻辑更贴合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:07:52