传递char*字面量调用TrimRight函数触发段错误的解决方法
字符串字面量调用TrimRight触发段错误的问题解析与解决
问题重现
调用TrimRight时,传递字符串字面量(char*)会触发段错误,但传递char[]则正常,函数代码如下:
void TrimRight(char* s) { if(!*s) return; char* end = 0; for(char c; c = *s; s++) { if(c == ' ') { if(end == 0) end = s; } else end = 0; } if(end) *end = '\0'; // 此处触发段错误:当s指向字符串字面量时 }
两种调用方式的本质差异
虽然你贴的汇编代码看起来地址传递逻辑一致,但内存区域的属性完全不同:
- 第一种调用:
char* text = "I'm a text";
这里的"I'm a text"是字符串字面量,编译后会被放在只读数据段(.rodata),text指针指向的是这片只读内存的地址。当TrimRight尝试通过*end = '\0'修改这片内存时,会触发内存保护机制,导致段错误。 - 第二种调用:
char text[] = "I'm a text";
这里的字符串字面量会被复制到text数组所在的内存区域(如果是局部变量则在栈上,全局变量则在可写数据段),这片内存是可写的,所以修改操作合法。
解决段错误的方法
方法1:确保传递可写的字符串
调用TrimRight时,始终传递可修改的字符数组,而不是直接传递字符串字面量的指针:
// 正确写法:用char[]存储字符串,再传递指针 char text[] = "I'm a text"; TrimRight(text);
方法2:修改TrimRight函数,内部处理可写副本
如果无法保证调用者传递可写内存,可以修改函数,先把输入字符串复制到堆内存或栈内存的可写区域,处理后再返回结果(注意内存管理):
#include <stdlib.h> #include <string.h> char* TrimRight(const char* s) { if (!s || !*s) return strdup(""); char* copy = strdup(s); if (!copy) return NULL; char* end = NULL; char* ptr = copy; for (char c; c = *ptr; ptr++) { if (c == ' ') { if (!end) end = ptr; } else end = NULL; } if (end) *end = '\0'; return copy; } // 使用示例 int main() { const char* text = "I'm a text"; char* trimmed = TrimRight(text); // 使用trimmed... free(trimmed); // 记得释放内存 return 0; }
关于“访问/修改字符串字面量(规避只读限制)”
从C标准角度来说,字符串字面量的类型是const char[],强制修改它属于未定义行为,即使某些编译器提供了绕过方法(比如GCC的-fwriteable-strings编译选项),也不建议使用:
- 这种方法完全不具备移植性,换个编译器或平台就会失效;
- 字符串字面量可能被合并(相同字面量共享内存),修改一个会影响其他地方的引用,导致难以排查的BUG;
- 现代操作系统的内存保护机制会阻止对只读段的写入,强制修改可能直接触发程序崩溃。
内容的提问来源于stack exchange,提问作者Gauliux
相关产品推荐
相关产品推荐

