为何在C语言中可重新赋值字符串常量指针?修改字符却报错?
字符串指针的赋值与修改差异解析
一、为什么msg = "New string"可以正常执行?
先理清两个关键概念:
char *msg是一个指针变量,它本身存放在栈内存中,属于可读写的变量,作用就是保存一块内存的起始地址。"Hello"、"New string"这类字符串字面量,是C语言的字符串常量,编译器会把它们放在程序的只读数据段(.rodata)里——这块内存的内容不允许修改,但它的起始地址可以被读取和传递。
看代码示例1:
char * msg = "Hello";
这行代码是把只读段中"Hello"的首地址,赋值给栈上的指针变量msg。
而msg = "New string";这一步,只是把另一个字符串常量"New string"的首地址,重新写入到指针变量msg中——本质是修改了指针变量自身的值(也就是它指向的目标地址),完全没有触碰只读段里的字符串内容。因为栈上的指针变量本身是可写的,所以这个操作完全合法。
最后printf输出的是msg当前指向的"New string",自然能正常打印。
二、为什么修改字符串字符会触发段错误?
看代码示例2:
char * msg = "Hello"; *(msg + 1) = 'a';
此时msg指向的是只读数据段中"Hello"的首地址,*(msg+1)对应的是这个字符串的第二个字符'e'。当你试图给这个位置赋值'a'时,本质是在向只读内存区域写入数据,这违反了操作系统的内存保护规则,直接触发段错误(Segmentation Fault)。
额外说明:*(msg + 1) = "a";这行代码还有类型不匹配的问题——"a"是const char*类型的指针,而左边*(msg+1)是char类型的变量,编译器通常会给出警告,但运行时依然会因为尝试写入只读内存而触发段错误。
总结
- 指针变量本身存放在栈上,是可读写的,所以可以重新赋值它指向的地址。
- 字符串字面量存储在只读数据段,其内容不允许修改,任何写入操作都会触发内存保护错误。
- 如果需要可修改的字符串,应该用
char msg[] = "Hello";(栈上的字符数组)或者通过malloc动态分配堆内存。
内容的提问来源于stack exchange,提问作者Martin Zeltin
相关产品推荐
相关产品推荐

