使用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)本质上是两步操作的封装:
- 调用
malloc(strlen(token) + 1),分配刚好能容纳token字符串(含终止符)的内存 - 将token的内容复制到这块新内存中
- 返回指向该内存的指针
所以执行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_ratof无法识别非法浮点数输入(会返回0.0),需要严谨处理的话可以用strtod- 所有动态分配的内存必须在不再使用时释放,避免内存泄漏
内容的提问来源于stack exchange,提问作者DJABRI MAROUANE
相关产品推荐
相关产品推荐

