C语言strtok函数处理CSV空值问题求助
问题:使用strtok读取CSV时丢失空字段并触发段错误
CSV测试数据
999999999,AA999999999,20240121,Uimo,Jacob,19910306,,,,,9999999999,Sam,Gok
现有实现代码
#include <stdio.h> #include <string.h> int main() { char *inFile; char line[8192]; int rowIndex = 0; const char *filename = "TestFile.csv"; // 补充缺失的filename定义 if ((inFile = fopen(filename, "r")) == NULL) { printf("Could not open input file [%s]\n", filename); return 1; } // Skip the header line fgets(line, sizeof(line) - 1, inFile); while (fgets(line, sizeof(line) - 1, inFile) != NULL) { char *token = strtok(line, ","); int fieldIndex = 0; printf("************** RECORD %d **************\n", rowIndex); while(fieldIndex < 13) { if (strlen(token) == 0) { token = " "; // 原代码单引号赋值错误,需用双引号字符串 printf("Field %d: '%s'\n", fieldIndex, token); } else { printf("Field %d: '%s'\n", fieldIndex, token); } token = strtok(NULL, ","); fieldIndex++; } rowIndex++; } fclose(inFile); return 0; }
当前错误输出
************** RECORD 0 ************** Field 0: '999999999' Field 1: 'AA999999999' Field 2: '20240121' Field 3: 'Uimo' Field 4: 'Jacob' Field 5: '19910306' Field 6: '9999999999' Field 7: 'Sam' Field 8: 'Gok ' Segmentation fault (core dumped)
期望正确输出
************** RECORD 0 ************** Field 0: '999999999' Field 1: 'AA999999999' Field 2: '20240121' Field 3: 'Uimo' Field 4: 'Jacob' Field 5: '19910306' Field 6: ' ' Field 7: ' ' Field 8: ' ' Field 9: ' ' Field 10: '9999999999' Field 11: 'Sam' Field 12: 'Gok'
问题分析与解决方案
核心问题
- strtok的局限性:strtok会自动跳过连续分隔符,无法识别两个逗号间的空字段,直接丢失了第6-9位的空值。
- 空指针访问错误:所有有效token读取完毕后,
token变为NULL,此时调用strlen(token)触发段错误。 - 未处理换行符:
fgets读取的行包含末尾\n,导致最后一个字段带换行符。
修正方案
放弃strtok,改为手动遍历字符串分割字段,处理空字段与剩余字段填充:
#include <stdio.h> #include <string.h> int main() { FILE *inFile; // 修正文件指针类型,原代码char*错误 char line[8192]; int rowIndex = 0; const char *filename = "TestFile.csv"; if ((inFile = fopen(filename, "r")) == NULL) { printf("Could not open input file [%s]\n", filename); return 1; } // Skip the header line fgets(line, sizeof(line) - 1, inFile); while (fgets(line, sizeof(line) - 1, inFile) != NULL) { // 去除行末尾换行符 size_t len = strlen(line); if (len > 0 && line[len-1] == '\n') { line[len-1] = '\0'; } char *current = line; int fieldIndex = 0; printf("************** RECORD %d **************\n", rowIndex); while(fieldIndex < 13) { char *comma_pos = strchr(current, ','); char field[256] = {0}; if (comma_pos != NULL && comma_pos > current) { // 非空字段,复制内容 strncpy(field, current, comma_pos - current); current = comma_pos + 1; printf("Field %d: '%s'\n", fieldIndex, field); } else if (comma_pos == current) { // 空字段(连续逗号) printf("Field %d: ' '\n", fieldIndex); current = comma_pos + 1; } else { // 最后一个字段或无更多字段 if (current != NULL && *current != '\0') { strcpy(field, current); printf("Field %d: '%s'\n", fieldIndex, field); } else { // 剩余字段填充空格 printf("Field %d: ' '\n", fieldIndex); } current = NULL; // 标记无更多字段 } fieldIndex++; } rowIndex++; } fclose(inFile); return 0; }
关键修正点
- 修正文件指针类型:将
char *inFile改为FILE *inFile,符合C标准文件操作要求。 - 去除换行符:读取行后立即清除末尾
\n,避免字段包含无效换行。 - 手动分割字段:用
strchr定位逗号,区分空字段、非空字段与末尾字段。 - 剩余字段填充:所有字段读取完毕后,剩余位置用空格填充,确保输出13个字段。
- 空指针防护:判断
current有效性,避免访问空指针触发错误。
内容的提问来源于stack exchange,提问作者Marco Somoza
相关产品推荐
相关产品推荐

