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个字符)。用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;从后往前插入空格
为了避免前面的插入操作影响后续空格的索引,需要从最后一个空格开始往前处理: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
相关产品推荐
相关产品推荐

