使用strtok处理CSV文件的C程序调试求助:逗号转斜杠功能异常
问题排查与修复方案
以下是你的代码存在的核心问题及对应修复后的完整代码:
核心问题分析
- 变量命名冲突:
main函数中profile* profile的变量名与结构体类型名重复,导致编译错误。 - 行读取方式错误:
fscanf("%s")会在遇到空格时停止读取,无法完整读取CSV整行内容;且格式串中的\n无意义。 - 未初始化结构体字段:当CSV行字段数量不足6个时,未赋值的字段会保留内存垃圾值,输出时出现乱码。
- 固定字段限制:原结构体仅支持最多6个字段,且打印时强制输出所有6个字段,导致多余的空斜线。
- 缓冲区溢出风险:使用
strcpy未限制长度,若字段内容超过数组大小会导致内存溢出。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct profile { char fields[6][30]; // 最多存储6个字段,每个字段30字节 int num_fields; // 记录实际字段数量 struct profile* next; } profile; profile* createProfile(char* line); profile* addLast(profile* item, profile* head); void printList(profile* head); void freeList(profile* head); int main() { FILE* file; char input[256]; printf("Enter filename: "); scanf("%s", input); file = fopen(input, "r"); if(file == NULL) { printf("Error opening file\n"); return 1; } profile* head = NULL; char line[256]; while(fgets(line, sizeof(line), file) != NULL) { // 去除行尾的换行符 size_t len = strlen(line); if(len > 0 && line[len-1] == '\n') { line[len-1] = '\0'; } profile* new_profile = createProfile(line); head = addLast(new_profile, head); } fclose(file); printList(head); freeList(head); return 0; } profile* createProfile(char* line) { profile* newProfile = malloc(sizeof(profile)); if(newProfile == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } // 初始化所有字段为空字符串 for(int i=0; i<6; i++) { memset(newProfile->fields[i], 0, sizeof(newProfile->fields[i])); } newProfile->num_fields = 0; newProfile->next = NULL; char* token = strtok(line, ","); while(token != NULL && newProfile->num_fields < 6) { // 使用strncpy避免缓冲区溢出 strncpy(newProfile->fields[newProfile->num_fields], token, sizeof(newProfile->fields[0])-1); newProfile->num_fields++; token = strtok(NULL, ","); } return newProfile; } profile* addLast(profile* item, profile* head) { if(head == NULL) { return item; } profile* current = head; while(current->next != NULL) { current = current->next; } current->next = item; return head; } void printList(profile* head) { while(head != NULL) { for(int i=0; i<head->num_fields; i++) { if(i > 0) { printf("/"); } printf("%s", head->fields[i]); } printf("\n"); head = head->next; } } void freeList(profile* head) { profile* temp; while(head != NULL) { temp = head; head = head->next; free(temp); } }
关键修复点说明
- 变量名修正:将
main中的变量名改为new_profile,避免与结构体类型名冲突。 - 行读取优化:使用
fgets读取整行内容,并去除行尾换行符,确保完整读取CSV行。 - 字段计数与初始化:新增
num_fields字段记录实际字段数量,初始化所有字段为空字符串,避免垃圾值输出。 - 安全字符串拷贝:使用
strncpy替代strcpy,限制拷贝长度防止缓冲区溢出。 - 动态输出调整:打印时仅输出实际存在的字段,避免多余空斜线。
- 内存泄漏修复:新增
freeList函数释放链表内存,避免内存泄漏。
扩展说明(处理空字段)
若需要支持CSV中的空字段(如a,,b转换为a//b),strtok无法满足需求(会跳过连续分隔符),需实现自定义分割函数。可将结构体改为动态数组存储字段,示例代码可参考以下思路:
- 使用
strchr遍历字符串分割字段,保留空字段 - 动态分配字段数组内存
- 打印时保留空字段对应的空字符串输出
内容的提问来源于stack exchange,提问作者manuel
相关产品推荐
相关产品推荐

