You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用strtok处理CSV文件的C程序调试求助:逗号转斜杠功能异常

问题排查与修复方案

以下是你的代码存在的核心问题及对应修复后的完整代码:

核心问题分析

  1. 变量命名冲突:main函数中profile* profile的变量名与结构体类型名重复,导致编译错误。
  2. 行读取方式错误:fscanf("%s")会在遇到空格时停止读取,无法完整读取CSV整行内容;且格式串中的\n无意义。
  3. 未初始化结构体字段:当CSV行字段数量不足6个时,未赋值的字段会保留内存垃圾值,输出时出现乱码。
  4. 固定字段限制:原结构体仅支持最多6个字段,且打印时强制输出所有6个字段,导致多余的空斜线。
  5. 缓冲区溢出风险:使用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);
    }
}

关键修复点说明

  1. 变量名修正:将main中的变量名改为new_profile,避免与结构体类型名冲突。
  2. 行读取优化:使用fgets读取整行内容,并去除行尾换行符,确保完整读取CSV行。
  3. 字段计数与初始化:新增num_fields字段记录实际字段数量,初始化所有字段为空字符串,避免垃圾值输出。
  4. 安全字符串拷贝:使用strncpy替代strcpy,限制拷贝长度防止缓冲区溢出。
  5. 动态输出调整:打印时仅输出实际存在的字段,避免多余空斜线。
  6. 内存泄漏修复:新增freeList函数释放链表内存,避免内存泄漏。

扩展说明(处理空字段)

若需要支持CSV中的空字段(如a,,b转换为a//b),strtok无法满足需求(会跳过连续分隔符),需实现自定义分割函数。可将结构体改为动态数组存储字段,示例代码可参考以下思路:

  • 使用strchr遍历字符串分割字段,保留空字段
  • 动态分配字段数组内存
  • 打印时保留空字段对应的空字符串输出

内容的提问来源于stack exchange,提问作者manuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:25:22