C++ 为什么修改指向字符串的指针的内容是错误的?

C++ 为什么修改指向字符串的指针的内容是错误的?,c++,C++,如果我写: char *aPtr = "blue"; //would be better const char *aPtr = "blue" aPtr[0]='A'; 我有个警告。上面的代码可以工作,但不是标准的,它有一个未定义的行为,因为它是只读内存,指针指向string literal。问题是: 为什么是这样? 使用此代码,而不是: char a[]="blue"; char *aPtr=a; aPtr[0]='A'; 没关系。我想了解在幕后会发生什么首先是一个指向由编译器创建的只读值的

如果我写:

char *aPtr = "blue"; //would be better const char *aPtr = "blue"
aPtr[0]='A';
我有个警告。上面的代码可以工作,但不是标准的,它有一个未定义的行为,因为它是只读内存,指针指向string literal。问题是: 为什么是这样? 使用此代码,而不是:

char a[]="blue";
char *aPtr=a;
aPtr[0]='A';

没关系。我想了解在幕后会发生什么

首先是一个指向由编译器创建的只读值的指针,该值放在程序的只读部分。无法修改该地址处的字符,因为它们是只读的

第二种方法创建一个数组,并从初始值设定项复制每个元素(有关详细信息,请参阅)。您可以修改数组的内容,因为它是一个简单的变量


第一个变量的工作方式是这样的,因为执行任何其他操作都需要动态分配一个新变量,并且需要垃圾收集来释放它。这不是C和C++如何工作的。

< P>字符串字符串不能被修改的主要原因(没有未定义的行为)是支持字符串文字合并。

很久以前,当内存比现在紧张得多时,编译器作者注意到许多程序都多次重复相同的字符串文字——特别是像模式字符串被传递到
fopen
(例如,
f=fopen(“filename”,“r”);
)和简单格式字符串被传递到
printf
(例如,
printf>)(%d\n,a);

为了节省内存,他们避免为这些字符串的每个实例分配单独的内存,而是分配一块内存,并将所有指针指向它

在一些情况下,他们甚至比合并那些不完全相同的文字更棘手。例如,考虑这样的代码:

printf("%s\t%d\n", a);
/* ... */
printf("%d\n", b);
在本例中,字符串文字不是完全相同的,但第二个文字是第一个文字结尾的相同部分。在本例中,它们仍然分配一段内存。一个指针指向内存的开头,另一个指针指向同一内存块中
%d
的位置

有可能(但不要求)字符串文字合并,基本上不可能说出修改字符串文字时会出现什么行为。如果合并了字符串文字,修改一个字符串文字可能会修改其他相同的字符串文字,或以相同的方式结束。如果未合并字符串文字,修改一个字符串文字将不会对任何其他字符串文字产生任何影响

MMU增加了另一个维度:它们允许将内存标记为只读,因此尝试修改字符串文字将导致某种类型的信号——但前提是系统具有MMU(这在一段时间内通常是可选的)而且还取决于编译器/链接器是否决定将它们标记为常量的字符串文本放在内存中

因为他们无法定义修改字符串文字时的行为,所以他们决定修改字符串文字将产生未定义的行为


第二种情况完全不同。在这里,您定义了一个字符数组。很明显,如果您定义了两个单独的数组,它们仍然是分开的,无论内容如何,因此修改一个数组不可能影响另一个数组。行为是明确的,并且一直如此,因此这样做会给出定义的行为。事实上,在estion可能是从字符串文字初始化的,但这并不会改变这一点。

无论是作为重复项关闭的字符串文字,还是@HappyCoder提到的字符串文字,都与此类似。这两个问题都涉及字符串文字的类型。这是问为什么字符串文字具有该类型。不仅仅是“会更好”;“这是合法的".Y'知道这已经被问了一百万次了。Ok的可能重复,如果我理解的话,在第一种情况下,编译器将字符串literal放在区域常量中,因此修改值不是不可能的。在第二种情况下,数组在堆栈上。是吗?是的。在这两种情况下,您声明的变量都在堆栈上,但不同变量类型。在第一种情况下,变量只是指针
p
,它指向存储在别处的常量数组。在第二种情况下,变量是数组
a
,它不指向任何地方,它是堆栈上的数组。您可以修改
a[0]
因为这是变量的一部分。您不能修改
p[0]
因为它是一个常量。即使不考虑合并,如果可以修改文本,那么
char*foo(){return“foo”;}foo()[0]='b';puts(foo());
do应该修改什么?或者允许
foo()的返回值
根据任意调用方对其所做的操作进行更改,或者每次调用时都需要分配一个新字符串,然后以某种方式对其进行垃圾收集。这两者都不是一个好的选择。@JonathanWakely:当然可以想象/假设(相当多)其他原因,文字合并在讨论为什么要这样做时有着根本性的不同:文字合并是在最初的C标准化过程中真正讨论过的(相当多),这导致了最初的C89/90标准。