使用fscanf()读取文件时为何发生段错误?
段错误原因分析与修复方案
你的代码触发段错误主要有以下几个核心问题,对应修复步骤如下:
1. 文件打开未做错误检查
如果./hw3.data不存在、路径错误或者没有读取权限,fopen会返回NULL,后续调用fscanf操作空指针直接触发段错误。必须在每次调用fopen后立刻检查返回值:
FILE *data = fopen("./hw3.data", "r"); if (data == NULL) { perror("Failed to open file"); exit(EXIT_FAILURE); }
2. 错误使用feof()判断循环终止
feof()只有在读取操作尝试越过文件末尾后才会返回真,这会导致你的scan()函数在文件读完后,还会多执行一次fscanf(此时读取失败,但size仍会被错误累加),后续malloc的空间如果超出实际需要,或者读取失败时操作非法内存,都会引发段错误。
正确的做法是用fscanf的返回值判断读取是否成功:fscanf返回成功匹配并读取的参数个数,你的格式串对应4个参数,返回值等于4时说明读取有效。修改scan()函数:
int scan(void) { int size = 0; FILE *data = fopen("./hw3.data", "r"); if (data == NULL) { perror("Failed to open file"); exit(EXIT_FAILURE); } struct data temp; // 改用局部变量,避免全局变量污染 int ret; while ((ret = fscanf(data, "%19s %f %d %19s", temp.name, &temp.floatNum, &temp.intNum, temp.color)) == 4) { size++; } fclose(data); // 别忘了关闭文件,避免资源泄漏 return size; }
3. 未限制字符串读取长度,存在缓冲区溢出风险
如果文件中name或color字段的长度超过结构体定义的20字节,fscanf会写入超出缓冲区的内存,破坏程序的内存布局,触发段错误。必须限制字符串读取长度:
// %19s 表示最多读取19个字符,留1个字节给字符串结束符'\0' fscanf(data, "%19s %f %d %19s", ...);
4. 其他细节问题
load()函数同样需要检查文件打开状态、限制字符串读取长度,并且读取后关闭文件。malloc可能返回NULL(内存不足),必须检查分配是否成功,使用完内存后要调用free释放。
完整修复后的代码
#include <stdlib.h> #include <stdio.h> struct data { char name[20]; float floatNum; int intNum; char color[20]; }; int scan(void) { int size = 0; FILE *data = fopen("./hw3.data", "r"); if (data == NULL) { perror("Failed to open file"); exit(EXIT_FAILURE); } struct data temp; int ret; while ((ret = fscanf(data, "%19s %f %d %19s", temp.name, &temp.floatNum, &temp.intNum, temp.color)) == 4) { size++; } fclose(data); return size; } void load(int size, struct data autos[]) { int i; FILE *data = fopen("./hw3.data", "r"); if (data == NULL) { perror("Failed to open file"); exit(EXIT_FAILURE); } for (i = 0; i < size; i++) { int ret = fscanf(data, "%19s %f %d %19s", autos[i].name, &autos[i].floatNum, &autos[i].intNum, autos[i].color); if (ret != 4) { fprintf(stderr, "Error reading line %d\n", i+1); exit(EXIT_FAILURE); } } fclose(data); } int main() { int size; struct data *autos; size = scan(); autos = malloc(size * sizeof(struct data)); if (autos == NULL) { perror("Failed to allocate memory"); exit(EXIT_FAILURE); } load(size, autos); free(autos); return 0; }
内容的提问来源于stack exchange,提问作者FunkyMunky
相关产品推荐
相关产品推荐

