实现strShiftLeft函数触发zsh: bus error问题排查求助
字符串左移函数引发总线错误/段错误的排查与修复
问题描述
实现了C语言函数char* strShiftLeft(char* str, int n),功能是将字符串左移n位(把前n个字符移到末尾),例如调用strShiftLeft("Thomas", 2)应返回"omasTh"。但编译运行后,Mac终端出现zsh: bus error ./a.out,在线编译器触发段错误,定位到两处写内存的代码疑似出错:
*(temp - n) = *(temp); *(temp + i) = *(temp_arr+i);
原代码
#include <stdio.h> #include <stdlib.h> char* strShiftLeft(char* str, int n) { // 如果传入字符串为NULL,返回NULL if (str == NULL) { printf("NULL!\n"); return NULL; } // 计算字符串长度 int len = 0; char* counter_ptr = str; while (*counter_ptr != '\0') { len++; counter_ptr++; } printf("len: %d\n", len); // 如果n大于字符串长度,返回NULL if (n > len) { printf("n too big!\n"); return NULL; } // 创建临时数组存储前n个字符,后续追加到字符串末尾 char temp_arr[n]; for (int i = 0; i < n; i++) { *(temp_arr + i) = *(str + i); } printf("temp_arr = %s\n", temp_arr); printf("str is still: %s\n", str); char* temp = str + n; printf("len - n = %d\n", len - n); // 更新字符串前(len - n)个字符(例如n=2时,"Thomas" -> "omasas") for (int i = 0; i < (len - n); i++) { printf("*temp = %c\n", *temp); printf("*(temp - n) = %c\n", *(temp - n)); *(temp - n) = *(temp); // 疑似错误行 temp++; } temp = str + (len - n); for (int i = 0; i < n; i++) { *(temp + i) = *(temp_arr+i); // 疑似错误行 } return str; } int main() { char* str = strShiftLeft("Thomas", 2); printf("%s\n", str); // 预期输出 "omasTh" return 0; }
错误原因
- 字符串字面量不可修改:
main函数中传入的"Thomas"是字符串字面量,C标准规定字符串字面量存储在只读数据段,任何试图修改它的操作都会触发内存访问错误(段错误/总线错误),这是两处写内存代码出错的根本原因。 - temp_arr未加终止符:
temp_arr是局部字符数组,只复制了n个字符但没有添加'\0',执行printf("temp_arr = %s\n", temp_arr)时会越界读取内存,导致未定义行为。
修复方案(符合限制要求)
关键点修改
- 将字符串字面量复制到可修改的栈数组中,再传入函数。
- 给
temp_arr添加字符串终止符,避免printf越界。
修改后的完整代码
#include <stdio.h> #include <stdlib.h> char* strShiftLeft(char* str, int n) { if (str == NULL) { printf("NULL!\n"); return NULL; } // 计算字符串长度(不使用strlen) int len = 0; char* counter_ptr = str; while (*counter_ptr != '\0') { len++; counter_ptr++; } printf("len: %d\n", len); if (n > len) { printf("n too big!\n"); return NULL; } // 临时存储前n个字符,并添加终止符 char temp_arr[n + 1]; // 多留一个位置存'\0' for (int i = 0; i < n; i++) { *(temp_arr + i) = *(str + i); } *(temp_arr + n) = '\0'; // 添加字符串终止符 printf("temp_arr = %s\n", temp_arr); printf("str is still: %s\n", str); char* temp = str + n; printf("len - n = %d\n", len - n); // 左移(len - n)个字符 for (int i = 0; i < (len - n); i++) { *(temp - n) = *(temp); temp++; } // 追加前n个字符到末尾 temp = str + (len - n); for (int i = 0; i < n; i++) { *(temp + i) = *(temp_arr + i); } // 确保字符串末尾的终止符不变(原字符串已有,此处可省略,但显式写更安全) *(str + len) = '\0'; return str; } int main() { // 将字符串字面量复制到可修改的栈数组中 char str[] = "Thomas"; char* result = strShiftLeft(str, 2); printf("%s\n", result); // 输出 "omasTh" return 0; }
验证说明
修改后运行程序,会正确输出omasTh,且不会触发内存错误:
- 栈数组
str是可写的,函数中对它的修改合法。 temp_arr添加了'\0',printf输出时不会越界。
内容的提问来源于stack exchange,提问作者sungenchuang7
相关产品推荐
相关产品推荐

