我有以下代码:
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
cout << a << ", " << b << endl;
return 0;
}
这编译和工作,即。打印bar,
bar
。现在我想证明这里发生的事情不是复制字符串。我想更改b
并显示a
也会发生变化。我想出了这个简单的代码:
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
b[1] = 'u'; // ← just this line added
cout << a << ", " << b << endl;
return 0;
}
......但它是段错误。为什么?有趣的是,以下修改运行得很好:
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char b[] = "bar"; // ← declaration changed here
a = b;
b[1] = 'u';
cout << a << ", " << b << endl;
return 0;
}
为什么它不像前一个那样发生错误?我想我错过了指针式和数组式字符串初始化之间的一些重要区别。
答案 0 :(得分:9)
您无法更改字符串常量,这是您在第一个代码示例中使用指向文字的语法时所获得的。
另请参阅此问题:Is a string literal in c++ created in static memory?。
答案 1 :(得分:6)
当你这样写:
char *b = "bar";
编译器分配一个匿名(无名)内存区域来存储字符串文字“bar”。字符串文字可能不会被修改,因此编译器(在链接器和操作系统的帮助下)将字符串文字放在正在运行的程序的写保护内存空间的一部分中。当您尝试修改它时,操作系统会捕获它并导致程序出现分段错误。
(你的代码是C ++,而不是C,但这与这个问题无关。)
答案 2 :(得分:2)
当你写:
char *foo = "bar";
实际发生的是“bar”存储在只读的内存段中。因此,它是不可改变的。您会因为尝试修改只读段而遇到段错误。
答案 3 :(得分:2)
您还可以通过打印指针的值来显示“a”已被更改。
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
cout << (void*)a << ", " << (void*)b << endl;
}
这将打印'a'和'b'指向的地址。
您必须转换为'void *',因为运算符&lt;&lt;为'char *'重载以打印出字符串,任何其他指针都将打印该地址。
答案 4 :(得分:1)
理论上,字符串文字不能分配给char *,只能分配给'const char *'。然后编译器会在你编写段错误代码之前阻止你。
答案 5 :(得分:-1)
这种差异可能是特定于编译器的。为了演示你的观点,使用malloc来分配缓冲区,然后将字符串复制到这个缓冲区中,当你不再需要字符串时不要忘记使用free。