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

使用strtok拆分字符串后strcpy给结构体字段触发段错误的问题

为什么strcpy触发段错误而strdup可行?正确的结构体字段赋值方式

段错误的根本原因

你的结构体Tenreg(注:代码中typedef的结构体应命名为Tenreg,main里的Buffer是其别名)中,name和departement是未初始化的char指针。在main中声明Buffer buffer;时,这两个指针会被赋予随机内存地址(野指针)。

strcpy(dest, src)的核心要求是:

  • dest必须指向已分配的可写内存
  • 内存大小要足够容纳src的所有字符(包括结尾的\0)

你的代码里buffer->departement是野指针,指向的内存要么是不可写的系统区域,要么不属于当前程序的地址空间,调用strcpy写入时必然触发段错误。

为什么strdup可以正常运行

strdup(token)本质上是两步操作的封装:

  1. 调用malloc(strlen(token) + 1),分配刚好能容纳token字符串(含终止符)的内存
  2. 将token的内容复制到这块新内存中
  3. 返回指向该内存的指针

所以执行buffer->departement = strdup(token);时,相当于给departement指针分配了合法的可写内存,复制操作自然不会出错。

正确的处理方式

方式一:使用固定长度字符数组(简单安全,适合已知最大长度的场景)

修改结构体定义,把指针换成固定大小的字符数组:

typedef struct {
    char name[64];          // 分配足够容纳最长名字的空间
    char departement[64];   // 同理分配部门字段的空间
    float salary;
} Tenreg;
typedef Tenreg Buffer; // 对应main里的Buffer别名

这样在main中声明Buffer buffer;时,name和departement已经拥有固定的可写内存,直接用strcpy即可:

strcpy(buffer->name, token);
strcpy(buffer->departement, token);

注意:为避免缓冲区溢出,建议用strncpy替代strcpy,并手动添加终止符:

strncpy(buffer->name, token, sizeof(buffer->name)-1);
buffer->name[sizeof(buffer->name)-1] = '\0';

方式二:动态分配内存(灵活,适合长度不确定的场景)

如果必须使用指针类型,需要手动管理内存的分配与释放:

// 读取函数中使用strdup的正确写法(包含内存分配检查)
void readEnregFromTextFile(char *fileName, Tenreg *buffer) {
    char string[256];
    char *delimiters = ",|;\n";
    FILE *f = fopen(fileName, "r");
    if (f == NULL) {
        printf("Error opening file\n");
        return;
    }

    if (fgets(string, sizeof(string), f) != NULL) {
        char *token = strtok(string, delimiters);
        if (token != NULL) {
            // 先释放旧内存(如果之前分配过)
            if (buffer->name != NULL) free(buffer->name);
            buffer->name = strdup(token);
            if (buffer->name == NULL) {
                printf("Memory allocation failed for name\n");
                fclose(f);
                return;
            }

            token = strtok(NULL, delimiters);
            if (token != NULL) {
                if (buffer->departement != NULL) free(buffer->departement);
                buffer->departement = strdup(token);
                if (buffer->departement == NULL) {
                    printf("Memory allocation failed for departement\n");
                    free(buffer->name); // 避免内存泄漏
                    fclose(f);
                    return;
                }

                token = strtok(NULL, delimiters);
                if (token != NULL) {
                    buffer->salary = atof(token);
                }
            }
        }
    } else {
        printf("Error reading from file\n");
    }

    fclose(f);
}

// main中使用后必须释放内存
int main() {
    Buffer buffer = {NULL, NULL, 0.0}; // 初始化指针为NULL
    readEnregFromTextFile("employee_data", &buffer);
    
    // 使用buffer处理数据...
    
    // 释放动态分配的内存
    free(buffer.name);
    free(buffer.departement);
    return 0;
}

额外注意事项

  • strtok是非线程安全的,多线程环境建议使用strtok_r
  • atof无法识别非法浮点数输入(会返回0.0),需要严谨处理的话可以用strtod
  • 所有动态分配的内存必须在不再使用时释放,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 21:35:54