为什么这个简单的字符串赋值是segfault?

时间:2009-03-05 09:31:34

标签: c++ string initialization

我有以下代码:

#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;
}

为什么它不像前一个那样发生错误?我想我错过了指针式和数组式字符串初始化之间的一些重要区别。

6 个答案:

答案 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。