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
相关产品推荐
相关产品推荐

