fscanf读取文件时while循环首次执行后意外跳出问题求助
问题分析与修复
1. 解决while循环提前跳出的问题
- 修正fscanf返回值判断:原代码用
!= EOF判断循环条件,但fscanf返回的是成功读取的参数个数。如果某次读取格式不匹配(比如缓冲区溢出导致内存破坏),返回值会小于2但不是EOF,直接终止循环。正确的条件应为fscanf(f, "%s %d", serial, &n) == 2,确保每次成功读取字符串和整数两个参数。 - 简化格式字符串:
%s和%d会自动跳过空白字符(空格、换行等),原代码中的%*c和\n属于多余格式符,会导致不必要的匹配错误,简化为"%s %d"即可。 - 避免缓冲区溢出:输入的最长序列号如
OP001Y100SSID有13个字符,需定义char serial[14](包含字符串结束符\0),防止溢出破坏内存(比如损坏文件指针f,导致后续读取直接返回EOF)。
2. 修复for循环的逻辑错误
- 调整遍历范围:原代码遍历
j < i + 1,包含了未初始化的listProducts[i],应改为遍历已添加的产品j < i(i是待添加的新位置索引,初始为0时无已添加产品)。 - 修正匹配逻辑:添加
found标志位,遍历所有已有产品,找到匹配序列号则累加数量并标记;遍历结束后未找到匹配项,再将当前产品添加到listProducts[i],避免因单次不匹配就覆盖数据的错误。
修复后的代码示例
#include <stdio.h> #include <string.h> #define MAX_PRODUCTS 100 #define SERIAL_LENGTH 14 typedef struct { char serialID[SERIAL_LENGTH]; int n_items; } Product; int main() { FILE *f = fopen("a.txt", "r"); if (!f) { perror("Failed to open file"); return 1; } Product listProducts[MAX_PRODUCTS] = {0}; // 初始化结构体,避免垃圾值干扰 char serial[SERIAL_LENGTH]; int n, i = 0, j; while (fscanf(f, "%s %d", serial, &n) == 2) { int found = 0; // 遍历已有产品查找匹配序列号 for (j = 0; j < i; j++) { if (strcmp(serial, listProducts[j].serialID) == 0) { listProducts[j].n_items += n; found = 1; break; } } // 未找到匹配则添加新产品 if (!found && i < MAX_PRODUCTS) { strcpy(listProducts[i].serialID, serial); listProducts[i].n_items = n; i++; } } fclose(f); // 打印验证结果 for (j = 0; j < i; j++) { printf("Serial: %s, Items: %d\n", listProducts[j].serialID, listProducts[j].n_items); } return 0; }
关键说明
- 结构体初始化:用
{0}初始化数组,确保serialID初始为空字符串,避免strcmp比较垃圾值引发的未定义行为。 - 边界检查:添加
i < MAX_PRODUCTS的判断,防止数组越界。
内容的提问来源于stack exchange,提问作者Maryam Ghafarinia
相关产品推荐
相关产品推荐

