strtok_r返回NULL引发段错误问题求助
问题根源分析
你的问题出在混合使用strtok和strtok_r,并且重复使用已经被strtok修改过的原始buffer。
具体来说:
- 第一次用
strtok遍历buffer时,strtok会将字符串中的所有:分隔符替换成\0来分割子串。比如你的输入字符串3:IBE3674:02-04-2019:...,经过几次strtok调用后,buffer会变成3\0IBE3674\002-04-2019\0...(所有:都被替换为\0)。 - 当你后续重新将
c2 = buffer,并用strtok_r再次解析时,buffer已经不是原始的完整字符串了——里面的分隔符都被破坏了。所以第一次strtok_r能拿到"3",但第二次调用strtok_r(NULL, ":", &c1)时,因为找不到:(已经被改成\0了),直接返回NULL,这时候调用strlen(c)就会触发段错误。
修复方案
核心思路是:第一次检查匹配时,不要修改原始的buffer,而是使用它的副本;当需要完整解析时,再用未被修改的原始buffer。
修改后的代码示例:
char buffer[500]; // 循环读取文件内容 while(fgets(buffer, sizeof(buffer), f) != NULL){ // 去掉fgets带来的换行符,避免干扰后续解析 buffer[strcspn(buffer, "\n")] = '\0'; // 复制原始buffer到临时内存,用于第一次匹配检查,避免修改原buffer char *temp_buf = strdup(buffer); if (!temp_buf) { perror("strdup failed"); continue; } char *c = strtok(temp_buf, ":"); // 跳过前4个字段,拿到第5个字段(origen) for(int i = 0; i < 4; i++){ c = strtok(NULL, ":"); if (!c) break; // 防御性检查,避免输入格式错误导致崩溃 printf("%s\n", c); } int is_match = 0; if (c && strcmp(c, argp->origen) == 0){ c = strtok(NULL, ":"); if (!c) { free(temp_buf); continue; } printf("%s\n", c); if(strcmp(c, argp->destino) == 0){ is_match = 1; } } // 释放临时buffer free(temp_buf); // 匹配成功,用原始buffer完整解析 if (is_match){ lista_vuelo *nodo = malloc(sizeof(lista_vuelo)); if (!nodo) { perror("malloc failed"); continue; } char *save_ptr; // strtok_r的保存指针 char *c = strtok_r(buffer, ":", &save_ptr); if (!c) { free(nodo); continue; } nodo->IdReg = atoi(c); printf("\n%d test\n", nodo->IdReg); // 拿到第二个字段(IBE3674) c = strtok_r(NULL, ":", &save_ptr); if (!c) { free(nodo); continue; } // 防御性检查 printf("\n%s\n", c); nodo->Idvuelo = strndup(c, strlen(c)); // ... 后续其他字段的解析逻辑 // 记得在合适的地方释放nodo和Idvuelo的内存,避免泄漏 } }
额外注意事项
- 防御性检查:每次调用
strtok/strtok_r后,都要检查返回值是否为NULL,避免输入格式不符合预期时触发崩溃。 - 内存管理:
strdup和malloc分配的内存,一定要在使用完后用free释放,避免内存泄漏。 - 换行符处理:
fgets会把换行符\n也读入buffer,用strcspn去掉它,避免最后一个字段带有换行符导致比较或解析错误。
内容的提问来源于stack exchange,提问作者Opresor
相关产品推荐
相关产品推荐

