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

字符串解析函数访问指针元素时触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:22:49