字符串解析函数访问指针元素时触发Segmentation Fault求助
解析字符串为令牌时的段错误修复
你的代码触发段错误的核心原因有以下几个,逐个分析并给出修复方案:
问题分析
- 内存分配完全错误:
malloc(sizeof(input))里的input是指针类型,sizeof(input)得到的是指针本身的字节数(比如64位系统是8字节),根本不够存储多个字符串指针。更关键的是,你只分配了指针数组的空间,但每个指向单词的二级指针完全没分配内存,直接访问output[word_num][word_index]就是在操作野指针,必然触发段错误。 - 循环逻辑冗余低效:
for(int i = 0; i < strlen(input); i++)每次循环都调用strlen,会重复遍历字符串计算长度,效率极低;另外循环里判断input[i] == '\0'完全多余,因为strlen的结果就是字符串的有效长度,i永远不会走到终止符的位置。 - 未处理最后一个单词:循环结束后,最后一个单词没有添加字符串终止符,也没有给指针数组的末尾设置
NULL标记(这是命令行参数解析的常规做法,方便后续遍历)。
修复后的代码
下面是修正后的完整实现,包含内存错误处理和标准的令牌格式输出:
#include <stdio.h> #include <stdlib.h> #include <string.h> char **string_parser(char *input) { // 先统计输入中的单词数量 int word_count = 0; char *ptr = input; int in_word = 0; // 标记当前是否处于单词中 while (*ptr != '\0') { if (*ptr == ' ') { in_word = 0; } else if (!in_word) { in_word = 1; word_count++; } ptr++; } // 分配指针数组空间,多留一个位置存NULL作为结束标记 char **output = malloc((word_count + 1) * sizeof(char*)); if (output == NULL) { perror("malloc failed"); return NULL; } int word_num = 0; int word_len = 0; ptr = input; in_word = 0; // 逐个提取单词并分配内存 while (*ptr != '\0') { if (*ptr == ' ') { if (in_word) { // 为当前单词分配内存 output[word_num] = malloc(word_len + 1); if (output[word_num] == NULL) { perror("malloc failed"); // 分配失败时释放已分配的内存,避免泄漏 for (int i = 0; i < word_num; i++) { free(output[i]); } free(output); return NULL; } // 复制单词并添加终止符 strncpy(output[word_num], ptr - word_len, word_len); output[word_num][word_len] = '\0'; word_num++; word_len = 0; in_word = 0; } } else { word_len++; in_word = 1; } ptr++; } // 处理最后一个未被空格终止的单词 if (in_word) { output[word_num] = malloc(word_len + 1); if (output[word_num] == NULL) { perror("malloc failed"); for (int i = 0; i < word_num; i++) { free(output[i]); } free(output); return NULL; } strncpy(output[word_num], ptr - word_len, word_len); output[word_num][word_len] = '\0'; word_num++; } // 添加NULL标记,方便后续遍历 output[word_num] = NULL; return output; } // 测试示例 int main() { char *input = "this is a parser test."; char **tokens = string_parser(input); if (tokens == NULL) { return 1; } // 遍历输出令牌并释放内存 for (int i = 0; tokens[i] != NULL; i++) { printf("Token %d: %s\n", i, tokens[i]); free(tokens[i]); } free(tokens); return 0; }
关键优化点
- 先统计单词数量,确保指针数组的空间足够。
- 为每个单词单独分配内存,避免野指针访问。
- 加入内存分配失败的错误处理,同时释放已分配的内存,防止内存泄漏。
- 最后添加
NULL终止符,符合类似argv的格式,方便后续代码遍历令牌。 - 优化循环逻辑,避免重复计算字符串长度,提升运行效率。
内容的提问来源于stack exchange,提问作者Bernard Putnam Sproul
相关产品推荐
相关产品推荐

