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

传递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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:25:26