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

C语言中修改共享地址的字符指针触发段错误,原因何在?

为什么修改共享地址的字符串字面量会触发段错误?

嘿,你观察到的str1和str2地址相同,是因为编译器的字符串池(string pooling)优化——当多个字符指针指向完全相同的字符串字面量时,编译器会让它们共享同一个内存地址,避免重复存储相同的字符串,帮程序节省内存空间。

但这里踩了一个C语言里很常见的坑:字符串字面量是存储在只读数据段(read-only data segment)中的,操作系统会把这块内存标记为「只读」,不允许程序修改它。当你尝试通过*(str2+2)='O'去写这块内存时,就违反了内存的读写权限,操作系统会直接抛出段错误(Segmentation Fault)来终止程序,保护只读内存不被非法篡改。

具体拆解你的代码问题:

  • 字符串字面量的存储位置:"Sudhanshu"这种字符串字面量,在编译阶段就会被放到程序的只读数据区(比如Linux系统下的.rodata段),这块内存只能读取,绝对不能写入。
  • 指针指向的是只读内存:你写的char *str1="Sudhanshu";,其实是让str1这个指针指向了只读数据区里的"Sudhanshu",而不是可写的栈内存或者堆内存。
  • 共享地址的原因:编译器的字符串池优化会把相同的字符串字面量合并成一个,所以str1和str2自然指向同一块只读内存地址。
  • 修改触发错误的本质:当你调用update(str2)尝试修改*(str2+2)时,本质是在往只读内存里写数据,这直接触发了操作系统的内存保护机制,所以程序会崩掉。

怎么解决这个问题?

如果你需要修改字符串,得把字符串字面量复制到可写的内存区域里,常见的两种方式:

1. 使用栈上的字符数组

把字符串字面量复制到栈上的数组中,数组所在的栈内存是可写的:

#include<stdio.h>
void update(char *str2){
    *(str2+2)='O';
}
int main(){
    char str1[]="Sudhanshu"; // 字面量被复制到栈数组,可写
    char str2[]="Sudhanshu"; // 每个数组都是独立的栈内存,地址不同
    printf(" %s , %s ",str1,str2);
    update(str2);
    printf(" %s , %s ",str1,str2);
    if(str1==str2){
        printf("True\n");
    }else printf("False\n");
    return 0;
}

2. 使用堆内存分配

通过strdup或者malloc+strcpy把字符串复制到堆内存,堆内存也是可写的:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void update(char *str2){
    *(str2+2)='O';
}
int main(){
    char *str1=strdup("Sudhanshu"); // 复制字面量到堆内存,可写
    char *str2=strdup("Sudhanshu");
    printf(" %s , %s ",str1,str2);
    update(str2);
    printf(" %s , %s ",str1,str2);
    if(str1==str2){
        printf("True\n");
    }else printf("False\n");
    // 记得用完堆内存要释放,避免内存泄漏
    free(str1);
    free(str2);
    return 0;
}

最后再补个小提醒:用==比较char*指针,其实是在比较指针的内存地址,而不是字符串的内容。如果要判断两个字符串的内容是否相同,应该用标准库的strcmp()函数哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:01:16