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

C语言中memmove移动内存后能否写入?附SIGBUS报错问询

动态字符串操作问题与解答

问题背景

尝试对已动态分配的字符串进行操作,避免丢失原指针以防止外部free时出错。算法要求:接收含多个单词的动态分配字符串,若单词数为偶数,将单词间空格设为2个,否则保留1个。

代码实现

char* evenNumOfWords(char* str)
{
    int spaceCounter = 0; // 统计空格出现次数
    int spaceIndices[strlen(str)]; // 保存所有空格的索引,避免遍历整个数组两次
    char* endPointer = str + strlen(str);
    int length;
    for (int i = 0 ; i < strlen(str) ; i++)
    {
        if(str[i] == ' ')
        {
            spaceIndices[spaceCounter] = i;
            spaceCounter++;
        }
    }
    if (spaceCounter % 2 == 1) { // 空格数为奇数时,单词数为偶数
        for (int i = 0 ; i < spaceCounter ; i++)
        {
            length = (int)(endPointer - str);
            memmove(str + spaceIndices[i] * sizeof(char) + 1, str + spaceIndices[i] * sizeof(char), length - spaceIndices[i] + 1); // 从空格位置开始将字符串后移1字节
            endPointer++;
            str[spaceIndices[i]] = ' ';
        }
    }
    return str;
}

遇到的错误

程序终止并返回code 138(被信号10:SIGBUS中断),经查是写入不可写内存导致。核心疑问:使用memmove移动数据后,能否写入原内存区域?


问题分析与解答

核心问题解答

memmove完全允许写入原内存区域,它的设计本身就是用来处理内存重叠场景的,你的错误和memmove的这个特性无关,根源在于内存空间不足。

错误原因拆解

动态分配的字符串有固定的内存容量,当你要把单个空格改成两个时,字符串总长度会增加,但你没有提前为新增的字符分配额外内存。每次执行memmove后写入新空格时,最终会超出原内存块的边界,访问到不可写的内存区域,触发SIGBUS信号。

另外,代码中还有一个隐藏问题:你保存的spaceIndices是原字符串的空格索引,但从前往后插入空格时,前面的插入会导致后续字符的位置偏移,后面的索引会失效,导致插入位置错误。

修复方案

  1. 提前计算并扩容内存
    先计算需要的新长度:当单词数为偶数(空格数为奇数)时,新长度 = 原字符串长度 + 空格数(每个空格新增1个字符)。用realloc重新分配足够的内存:

    size_t orig_len = strlen(str);
    // 计算新长度:原长度 + 要新增的空格数(每个原空格加1个)
    size_t new_len = orig_len + spaceCounter;
    // 重新分配内存,+1是为字符串终止符'\0'预留空间
    char* resized_str = realloc(str, new_len + 1);
    if (!resized_str) {
        // 内存分配失败,返回原字符串(根据需求处理错误)
        return str;
    }
    str = resized_str;
    
  2. 从后往前插入空格
    为了避免前面的插入操作影响后续空格的索引,需要从最后一个空格开始往前处理:

    if (spaceCounter % 2 == 1) {
        char* end_ptr = str + orig_len;
        // 从后往前遍历空格索引
        for (int i = spaceCounter - 1; i >= 0; i--) {
            int idx = spaceIndices[i];
            // 把从idx开始的字符后移1位
            memmove(str + idx + 1, str + idx, (end_ptr - str) - idx);
            // 写入第二个空格
            str[idx] = ' ';
            end_ptr++;
        }
        // 别忘了更新字符串终止符
        *end_ptr = '\0';
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:25:09