为何两次调用fgets()可正常运行,单次调用却不行?
为什么两次调用
fgets()正常,单次却不行? 嘿,我来帮你捋清楚这个问题~ 先从你的代码和场景入手分析:
核心原因:数据文件格式和fgets调用次数不匹配
从你两次调用fgets的代码逻辑来看,大概率你的数据文件file__dat的格式是每一条设备信息(Name+MAC)对应两行内容——比如第一行是有效数据(Name,MAC格式),第二行是空行/换行符;或者第一行存Name,第二行存MAC。
两次fgets的逻辑刚好适配了这个格式:
- 第一次
fgets读取有效行,用strtok分割出Name和MAC,存入结构体; - 第二次
fgets读取那行不需要的内容(空行/第二字段行),相当于跳过它,让下一次循环的fgets能读到下一组有效数据。
而单次调用fgets时,循环会把所有行都当成有效数据处理:
- 如果遇到空行,
strtok分割不到任何内容,返回NULL,这时用strcpy把NULL拷贝到结构体里,会触发未定义行为(程序崩溃、乱码等); - 如果是一行存Name一行存MAC的格式,单次调用会把Name当成第一组的Name,下一行的MAC当成第二组的Name,直接导致数据完全错位。
验证方法:打印每次fgets的内容
你可以在代码里加打印,看看两次fgets分别读到了什么,就能一目了然:
for (i = 0; i < num; i++) { fgets(buff, 22, dat); printf("第一次fgets读到: |%s|\n", buff); // 用|包裹方便看空行/换行 printf("%s\n", buff); file = strtok(buff, ","); strcpy(aparell[i].Name, file); file = strtok(NULL, ","); strcpy(aparell[i].MAC, file); fgets(buff, 22, dat); printf("第二次fgets读到: |%s|\n", buff); }
如果第二次打印的是空行(||或者|\n|),那就是我说的情况了。
优化建议(给新手的小提醒)
- 必须检查文件打开是否成功:你现在直接
fopen后就用,万一文件不存在/权限不够,dat会是NULL,后续调用fgets直接崩:dat = fopen(file__dat, "r"); if (dat == NULL) { perror("打开文件失败"); // 打印具体错误原因 return 1; // 或者做其他错误处理 } - 加
strtok的空指针判断:防止读到无效行时程序崩溃:file = strtok(buff, ","); if (file == NULL) { printf("第%d行数据格式错误,跳过\n", i+1); continue; } strcpy(aparell[i].Name, file); file = strtok(NULL, ","); if (file == NULL) { printf("第%d行缺少MAC字段,跳过\n", i+1); continue; } strcpy(aparell[i].MAC, file); - 用
strncpy代替strcpy更安全:避免缓冲区溢出(比如Name字段太长超过结构体数组的长度):// 假设aparell[i].Name的长度是20,就这么写: strncpy(aparell[i].Name, file, sizeof(aparell[i].Name)-1); aparell[i].Name[sizeof(aparell[i].Name)-1] = '\0'; // 手动加字符串结束符
内容的提问来源于stack exchange,提问作者Agapito Gallart Bernat
相关产品推荐
相关产品推荐

