C语言如何解决从括号中提取单词存入结构体的strtok异常问题
问题原因
问题核心是strtok函数不可重入:strtok内部使用静态全局变量存储上一次拆分的位置上下文,同一进程内所有strtok调用共享这个上下文:
- 主函数第一次调用
strtok(row, "(")后,内部静态变量记录了当前的拆分位置 get_and_print_word函数中调用的strtok(r, " ")直接覆盖了strtok内部存储的主函数拆分上下文- 回到主函数执行
pch = strtok(NULL, "(")时,使用的是被覆盖的异常上下文,自然会返回错误的指针地址
解决方案
方案1:使用可重入拆分函数strtok_r(推荐)
strtok_r是POSIX标准提供的strtok线程安全/可重入版本,要求用户自行传入指针存储当前拆分的上下文,不同拆分流程的上下文完全独立不会互相干扰。
如果是Windows平台可以替换为strtok_s,参数逻辑完全一致。
修改后主函数代码:
int main(int argc, char * argv[]) { char row[] = "(octopus kitten) (game cake) (soccer football)"; char *pch, *main_ctx; // 单独存储主函数拆分流程的上下文 pch = strtok_r(row, "(", &main_ctx); while (pch != NULL) { pch[strcspn(pch, ")")] = '\0'; get_and_print_word(pch); pch = strtok_r(NULL, "(", &main_ctx); } return 0; }
修改后get_and_print_word函数代码:
void get_and_print_word(char str[]) { char r[4000]; strcpy(r, str); char *c, *sub_ctx; // 单独存储子拆分流程的上下文 c = strtok_r(r, " ", &sub_ctx); for (int i = 0; i < 2; i++) { printf("%s\n", c); c = strtok_r(NULL, " ", &sub_ctx); } }
方案2:先全量提取括号片段再统一处理
如果环境不支持strtok_r类的可重入拆分函数,可以先把所有括号内的字符串提取出来存入数组,全量提取完成后再遍历数组拆分每个片段的单词,避免两个strtok流程同时运行互相干扰。
int main(int argc, char * argv[]) { char row[] = "(octopus kitten) (game cake) (soccer football)"; char *pch; // 存储提取到的括号片段,可根据实际场景调整容量 char segments[10][100] = {0}; int seg_count = 0; // 第一步:仅提取所有括号内的片段存入数组 pch = strtok(row, "("); while (pch != NULL && seg_count < 10) { pch[strcspn(pch, ")")] = '\0'; strcpy(segments[seg_count++], pch); pch = strtok(NULL, "("); } // 第二步:统一处理每个片段拆分单词 for (int i = 0; i < seg_count; i++) { get_and_print_word(segments[i]); } return 0; }
内容的提问来源于stack exchange,提问作者MichaelLearner
相关产品推荐
相关产品推荐

