4

我有以下代码:

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

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

4

6 回答 6

9

您无法更改字符串常量,这是您在第一个代码示例中使用指向文字的语法时所得到的。

另请参阅此问题:C++ 中的字符串文字是在静态内存中创建的吗?.

于 2009-03-05T09:33:37.060 回答
6

当你写这个:

char *b = "bar";

编译器分配一个匿名(无名)内存区域来存储字符串文字“bar”。字符串文字可能不会被修改,因此编译器(在链接器和操作系统的帮助下)将字符串文字放在正在运行的程序的一部分写保护的内存空间中。当您尝试修改它时,操作系统会捕获它并导致您的程序出现分段错误。

(您的代码是 C++,而不是 C,但这与这个问题无关。)

于 2009-03-05T09:34:41.050 回答
2

当你写:

char *foo = "bar";

实际发生的是“条”存储在内存的只读段中。因此,它是不可变的。你得到一个段错误,因为你试图修改一个只读段。

于 2009-03-05T09:35:07.757 回答
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*' 因为运算符 << 为 'char*' 重载以打印出任何其他指针将打印地址的字符串。

于 2009-03-05T09:43:52.213 回答
1

理论上,不应将字符串文字分配给 char*,而只能分配给 'const char*'。然后编译器会在你编写段错误代码之前阻止你。

于 2009-03-05T11:44:33.500 回答
-1

这种差异可能是特定于编译器的。为了证明您的观点,请使用 malloc 分配缓冲区,然后将字符串复制到此缓冲区中,并且当您不再需要该字符串时不要忘记使用 free 。

于 2009-03-05T09:34:58.117 回答