Win32程序调用fscanf导入CSV触发段错误,gdb定位到ungetwc报错
段错误触发原因及解决方法
触发原因
- 变量拼写错误+未初始化野指针:你定义的FILE指针变量名为
sorgente,但实际代码中赋值、操作使用的变量名为source,变量名不匹配,在部分编译环境下会被识别为未定义的野指针。同时即使拼写一致,你将FILE指针定义在switch(msg)块的开头,C语言中switch块的case标签外的变量不会在进入对应case时自动初始化,若fopen返回NULL,后续执行fclose(source)相当于对空指针执行释放操作,直接触发段错误。 - 读取逻辑错误导致数组越界:你使用
!feof(source)作为循环判断条件,feof仅在读取操作失败后才会返回真,该逻辑会导致最后一次读取失败后仍执行i++操作,若CSV文件行数超过1000行,会越界访问全局数组user,触发内存访问错误。 - 缓冲区无长度限制导致溢出:结构体中
name字段仅15字节长度,你使用%[^,]格式符读取字符串时未限制长度,若CSV中name字段长度超过14字节(需留1字节存储字符串终止符\0),会发生缓冲区溢出,破坏内存结构触发段错误。 - 字符编码不匹配:你使用的窗口过程为宽字符版本
DefWindowProcW,若VSCode编译环境默认开启宽字符配置,fscanf处理编码不匹配的CSV文件时会触发内部宽字符处理函数ungetwc报错,就是你gdb调试时看到的错误。
解决方法
- 修正变量拼写与作用域:将FILE指针定义在IMPORT的case块内部,初始化为NULL,仅当fopen成功时才执行fclose操作:
case IMPORT:{ int i = 0; FILE *source = NULL; // 块内定义并初始化,变量名统一为source if ((source = fopen("./Data/users.csv", "r")) == NULL) { printf("can't open the file.\n"); } else { // 读取逻辑 fclose(source); // 仅打开成功时关闭 } break; }
- 修正文件读取逻辑:直接用fscanf的返回值作为循环判断条件,同时限制读取行数不超过数组容量,限制字符串读取长度避免溢出:
// 最多读1000条,%14[^,]限制name最长14字节,返回值为4表示4个字段全部读取成功 while(i < 1000 && fscanf(source,"%14[^,],%d,%f,%f\n", user[i].name, &user[i].born, &user[i].price, &user[i].average) == 4) { i++; }
- 统一字符编码:若CSV文件为UTF-8编码,可在fopen后添加编码声明,或调整编译选项将窗口字符集与文件读取字符集统一,避免宽字符处理错误。
- 补充边界判断:可在读取完成后添加i的数值打印,确认读取行数是否符合预期,避免异常越界。
内容的提问来源于stack exchange,提问作者diane fink
相关产品推荐
相关产品推荐

