C语言读取CSV到结构体数组指针异常问题求助
问题原因分析
你遇到的问题核心是指针指向的内存被重复覆盖:
- 结构体中的
id和day都是字符指针,你直接把strtok返回的指针赋值给它们,但strtok返回的是栈上buffer数组内部的地址。 - 每次循环执行
fgets(buffer, ...)时,都会把新的CSV行内容覆盖buffer里的旧数据。循环结束后,所有结构体的id和day指针都指向同一个buffer区域,自然输出的都是最后一行的内容。
另外你提到试过strcpy但没解决,大概率是因为你没有先给id和day指针分配内存,直接用strcpy往未初始化的指针里写数据,这属于未定义行为,根本无法正确复制内容。
解决方案
需要给每个结构体的id和day单独分配内存,再将strtok解析出的字符串复制到分配好的内存中。有两种常用方式:
方式1:使用strdup(推荐,简化代码)
strdup会自动分配内存并复制字符串(注意:这是POSIX标准函数,大部分编译器和系统都支持):
修改循环内的赋值代码:
// 解析ID data = strtok(buffer, ","); sample[counter].id = strdup(data); // 解析日期,加上\n避免包含换行符 data = strtok(NULL, ",\n"); sample[counter].day = strdup(data);
方式2:手动malloc + strcpy(纯C标准,兼容性更好)
如果需要严格遵循C标准,手动分配内存:
// 解析ID data = strtok(buffer, ","); sample[counter].id = malloc(strlen(data) + 1); // +1用于存储字符串结束符'\0' if (sample[counter].id == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } strcpy(sample[counter].id, data); // 解析日期 data = strtok(NULL, ",\n"); sample[counter].day = malloc(strlen(data) + 1); if (sample[counter].day == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } strcpy(sample[counter].day, data);
额外注意事项
- 解析日期时,
strtok的分隔符要加上\n,因为fgets会把行尾的换行符读进buffer,如果不处理,day会包含换行符,输出时可能出现多余空行。 - 程序结束前要记得释放分配的内存,避免内存泄漏:
for (int i = 0; i < counter; i++) { free(sample[i].id); free(sample[i].day); }
修改后的完整代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> struct Sample { char *id; char *day; }; int main (){ struct Sample sample[100]; char buffer[1000]; char *data; FILE *fp; fp = fopen("mwecsv.csv","r"); if (fp == NULL) { printf("Cannot open file"); exit(-1); } printf("file exists and opened\n"); // 跳过表头 fgets(buffer,sizeof(buffer),fp); printf("%s\n",buffer); int counter = 0; while(fgets(buffer,sizeof(buffer),fp)){ printf("***********\n%s\n******************\n",buffer); // 解析ID data = strtok(buffer,","); printf("first token is %s\n", data); sample[counter].id = strdup(data); // 解析日期,包含\n作为分隔符 data = strtok(NULL,",\n"); printf("second token is %s\n", data); sample[counter].day= strdup(data); counter++; } fclose(fp); // 输出结果 for (int i = 0; i < counter; i++) printf("%s %s\n", sample[i].id, sample[i].day); printf("\n"); // 释放内存 for (int i = 0; i < counter; i++) { free(sample[i].id); free(sample[i].day); } return 0; }
运行这段代码后,就能得到你期望的输出:
Schd5 Monday Schd3 Tuesday
内容的提问来源于stack exchange,提问作者CProgrLearner
相关产品推荐
相关产品推荐

