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

C语言char*分割为char**时触发Segmentation fault段错误排查

段错误核心原因

你的代码存在两处明确的未定义行为,这是故障偶现、valgrind环境下无法复现的根本原因:

  • 非法释放非堆内存
    查看main函数中的逻辑:
    char *buffer = malloc(sizeof(char) * 100);
    buffer = "hello world !\n";
    // ...
    free (buffer);
    
    你先通过malloc申请了100字节堆内存,紧接着直接将buffer指针指向了只读数据段存储的字符串常量,不仅造成了之前申请的堆内存泄漏,后续调用free(buffer)时,释放的根本不是堆地址,而是只读常量区的地址,会直接破坏进程堆的管理结构。
    第一次调用get_words不崩溃属于概率事件:堆结构被破坏后,第二次调用malloc为words分配内存时,极有可能返回非法地址,访问时就会触发段错误。valgrind会替换默认的内存分配实现,对非法free操作的容错性更高,因此不会立刻崩溃。
  • 潜在的只读内存写入风险
    你直接将字符串字面量作为参数传入get_words,这类常量存储在只读内存页中,只要出现写入操作就会立刻触发段错误。虽然当前版本的get_words没有修改入参内容,但后续迭代如果新增修改入参的逻辑,会直接触发故障。
  • 额外的越界隐患
    你当前固定为words数组分配4096个char*指针、每个指针分配4096字节,内存浪费严重;如果输入的单词数超过4096、单个单词长度超过4095(需预留1字节存\0),就会出现数组越界,同样会触发段错误。
修复方法
  1. 修正字符串赋值与内存释放逻辑:如果要将字符串存入malloc申请的堆缓冲区,使用strcpy完成拷贝,禁止直接修改指针指向;仅对自己申请的堆地址执行free操作:
    // 错误写法
    // char *buffer = malloc(sizeof(char) * 100);
    // buffer = "hello world !\n";
    
    // 正确写法
    char *buffer = malloc(sizeof(char) * 100);
    strcpy(buffer, "hello world !\n");
    // 使用完buffer后再释放
    free(buffer);
    
  2. 为get_words增加边界校验:如果保留预分配逻辑,需要判断当前写入的单词数、单单词长度是否超出预分配的内存大小,避免越界写入。更合理的实现是先遍历输入统计单词数、每个单词的长度,按需分配内存,避免空间浪费和越界风险。
  3. 明确只读入参的属性:如果get_words不会修改传入的buffer内容,将形参类型改为const char *buffer,从编译层面拦截误修改只读内存的操作。
  4. 配套实现words数组的释放函数,避免内存泄漏。
修复后可稳定运行的示例代码
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>

char **get_words(const char *buffer, char delimiter)
{
    printf("buffer = %s\n", buffer);
    char **words = malloc(sizeof(char *) * 100);
    if (words == NULL) {
        printf("Malloc Error\n");
        exit(84);
    }
    for (int i = 0; i < 100; i++) {
        words[i] = malloc(sizeof(char) * 100);
        if (words[i] == NULL) {
            printf("Malloc Error\n");
            exit(84);
        }
    }
    int word_count = 0;
    int l = 0;
    for (int i = 0; buffer[i] != '\0' && buffer[i]  != '\n'; i++, l++) {
        // 增加边界判断,避免越界
        if (word_count >= 99 || l >= 99) break;
        if (buffer[i] == delimiter) {
            words[word_count][l] = '\0';
            word_count++;
            l = -1;
        }
        else
            words[word_count][l] = buffer[i];
    }
    words[word_count][l] = '\0';
    // 末尾置NULL标记数组结束
    words[word_count + 1] = NULL;
    return words;
}

void free_words(char **words)
{
    for (int i = 0; i < 100; i++) {
        free(words[i]);
    }
    free(words);
}

int main()
{
    char *buffer = malloc(sizeof(char) * 100);
    strcpy(buffer, "hello world !\n");
    char **words = get_words(buffer, ' ');
    printf("words[0]= %s\n", words[0]);
    free(buffer);
    free_words(words);

    char **reply = get_words("Second call\n", ' ');
    printf("reply[0] = %s\n", reply[0]);
    free_words(reply);
    return 0;
}

内容的提问来源于stack exchange,提问作者cricciardi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 04:48:30