C语言CSV读取技术求助:表头存入header数组并指定格式打印
C语言CSV读取与表头使用问题
需求说明
需要编写C语言程序,读取以下格式的CSV文件:
name,hp,damage duck,20,5 cat,30,10 giraffe,100,20
并按以下格式输出:
name:duck hp:20 damage:5 name:cat hp:30 damage:10 name:giraffe hp:100 damage:20
要求:必须将CSV的表头(原实际为韩文)存入名为header的数组,打印时必须使用该数组。
现有代码
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[1000]; int hp; int damage; } Monster; typedef struct { char header1[4]; char header2[2]; char header3[6]; } Header; int main() { FILE* fp = fopen("entityData.csv", "r"); if (!fp) { printf("Error opening file\n"); return 1; } Monster monsters[100]; int num_records = 0; char line[100]; Header headerList[20]; fgets(headerList, sizeof(headerList), fp); char *hd1, *hd2, *hd3; hd1 = strtok(headerList, ","); strncpy(monsters[num_records].name, hd1, 20); hd2 = strtok(NULL, ","); hd3 = strtok(NULL, "\n"); while (fgets(line, sizeof(line), fp)) { char* token = strtok(line, ","); strncpy(monsters[num_records].name, token, 20); token = strtok(NULL, ","); monsters[num_records].hp = atoi(token); token = strtok(NULL, ","); monsters[num_records].damage = atoi(token); num_records++; } for (int i = 0; i < num_records; i++) { printf("name:%s hp:%d damage:%d\n", monsters[i].name, monsters[i].hp, monsters[i].damage); } fclose(fp); return 0; }
问题分析与修正方案
核心问题
- 表头存储结构不合理:固定长度的
Header结构体无法适配韩文(UTF-8编码下每个韩文占3字节),容易出现截断或越界。 - 表头读取逻辑错误:直接用
fgets读取到结构体数组headerList是非法操作,且错误将表头内容存入了第一个Monster的name字段。 - 打印未使用表头数组:硬编码了输出前缀,不符合需求。
修正步骤
- 改用通用表头存储数组:定义二维字符数组
char header[3][100];,足够容纳韩文表头(避免长度限制问题)。 - 正确读取表头:先读取表头行到临时字符数组,再用
strtok分割后存入header数组。 - 修正数据读取逻辑:表头读取后不干扰数据行的存储,确保
num_records从0开始正确计数。 - 打印时使用表头数组:在
printf中直接引用header数组的元素,替换硬编码的前缀。
修正后的完整代码
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[1000]; int hp; int damage; } Monster; int main() { FILE* fp = fopen("entityData.csv", "r"); if (!fp) { printf("Error opening file\n"); return 1; } Monster monsters[100]; int num_records = 0; char header[3][100]; // 存储3个表头字段,每个字段最多100字符(适配韩文) char header_line[100]; // 读取表头行 if (fgets(header_line, sizeof(header_line), fp) != NULL) { // 分割表头并存入header数组 char* token = strtok(header_line, ",\n"); // 同时处理逗号和换行符 if (token != NULL) { strncpy(header[0], token, sizeof(header[0]) - 1); header[0][sizeof(header[0]) - 1] = '\0'; // 确保字符串终止 } token = strtok(NULL, ",\n"); if (token != NULL) { strncpy(header[1], token, sizeof(header[1]) - 1); header[1][sizeof(header[1]) - 1] = '\0'; } token = strtok(NULL, ",\n"); if (token != NULL) { strncpy(header[2], token, sizeof(header[2]) - 1); header[2][sizeof(header[2]) - 1] = '\0'; } } // 读取数据行 char line[100]; while (fgets(line, sizeof(line), fp)) { char* token = strtok(line, ",\n"); if (token != NULL) { strncpy(monsters[num_records].name, token, sizeof(monsters[num_records].name) - 1); monsters[num_records].name[sizeof(monsters[num_records].name) - 1] = '\0'; } token = strtok(NULL, ",\n"); if (token != NULL) { monsters[num_records].hp = atoi(token); } token = strtok(NULL, ",\n"); if (token != NULL) { monsters[num_records].damage = atoi(token); } num_records++; } // 使用header数组打印结果 for (int i = 0; i < num_records; i++) { printf("%s:%s %s:%d %s:%d\n", header[0], monsters[i].name, header[1], monsters[i].hp, header[2], monsters[i].damage); } fclose(fp); return 0; }
关键说明
- 表头数组
header[3][100]:每个字段预留100字符空间,完全适配韩文UTF-8编码的存储需求,避免长度不足问题。 - 分割表头时使用
,\n作为分隔符:同时处理逗号和换行符,避免表头字段末尾残留换行符。 - 所有字符串复制都添加了
-1的长度限制,并手动添加终止符:防止缓冲区溢出,保证字符串有效性。 - 打印时直接引用
header数组:完全符合需求,无论表头是英文还是韩文都能正确输出。
内容的提问来源于stack exchange,提问作者Mr Cake
相关产品推荐
相关产品推荐

