C语言读取txt逗号分隔浮点数存入二维数组仅首行正确如何解决
问题原因分析
- 表头读取逻辑错误
你使用fscanf(fp, "%s,", DUID)读取表头,而%s格式符会读取到空白符(换行、空格等)才停止,会把整个第一行表头全部读入DUID,并不会在第一个逗号处停止,这一步虽然不会直接导致后续读取失败,但逻辑不符合你的预期。
- 表头读取逻辑错误
fscanf匹配失败后指针不移动,且错误判断逻辑缺失
你的CSV文件中存在大量非数字内容:比如xxxxx/aaaa等非法字符串、两个逗号连在一起的空字段,%f格式符遇到这类非数字内容时,会直接匹配失败,返回成功匹配的字段数(而非EOF),同时文件指针停在错误位置不再移动,后续所有fscanf调用都会持续匹配失败,所以除了第一行数据刚好全部是合法数字读取成功外,剩下的所有行都读取失败,保留了数组初始化的0值。
- 退出逻辑错误
你仅在fscanf返回EOF时才退出循环,但匹配失败时返回值是小于4的整数,不会触发break,循环会一直跑完32次,所有失败的读取位置都保留初始0值。
- 退出逻辑错误
- 多余的
fclose调用
你对同一个文件指针调用了两次fclose,属于未定义行为,虽然不影响读取结果,但属于代码BUG。
- 多余的
修正方案
正确的读取逻辑应该是先逐行读取整行内容,再拆分每行的字段,对每个字段单独校验转换,避免非法字符导致后续读取全部失败。
修正后代码
#define _CRT_SECURE_NO_WARNINGS 1 #define ROWS 31 #define COLUMNS 4 #include <stdio.h> #include <stdlib.h> #include <string.h> void openFile(char* str) { FILE* fp; int x = 1; char s[124] = { 0 }; while (x == 1) { printf("Type the filename to process >\n"); scanf("%123s", s); if ((fp = fopen(s, "r")) == NULL) { printf("error: file not found\n\n"); x = 1; } else { fclose(fp); x = 0; } strcpy(str, s); } } // 校验字符串是否为合法浮点数,是就返回转换后的值,否则返回0 float parseNumber(const char* str) { if (str == NULL || *str == '\0') return 0.0f; char* endptr; float val = strtof(str, &endptr); // 整个字符串都被转换才是合法数字 if (endptr == str || *endptr != '\0') { return 0.0f; } return val; } int main() { FILE* fp; float data[ROWS][COLUMNS] = { 0 }; char filename[124]; char lineBuf[256]; // 每行缓存 openFile(filename); fp = fopen(filename, "r"); if (fp == NULL) return 1; // 丢弃第一行表头 fgets(lineBuf, sizeof(lineBuf), fp); int rows = 0; // 逐行读取,最多读ROWS行 while (rows < ROWS && fgets(lineBuf, sizeof(lineBuf), fp) != NULL) { // 去掉行尾的换行符 lineBuf[strcspn(lineBuf, "\r\n")] = '\0'; char* token = strtok(lineBuf, ","); int col = 0; while (token != NULL && col < COLUMNS) { data[rows][col] = parseNumber(token); token = strtok(NULL, ","); col++; } rows++; } fclose(fp); // 输出结果 for (int row = 0; row < rows; row++) { printf("This is row %d = %f, %f, %f, %f\n", row, data[row][0], data[row][1], data[row][2], data[row][3]); } return 0; }
改动说明
- 先调用
fgets读取整行表头直接丢弃,符合预期逻辑 - 新增
parseNumber函数处理非法字段,遇到空值、非数字字符串统一返回0,不会中断后续读取 - 使用
strtok按逗号拆分每行的字段,逐字段转换,避免非法字符导致整个读取流程阻塞 - 移除了多余的
fclose调用,修正了数组定义的ROWS、COLUMNS为实际需要的31、4,避免空间浪费
内容的提问来源于stack exchange,提问作者Paolo Robillos
相关产品推荐
相关产品推荐

