为什么我在一种情况下会收到带有字符串文字的弃用转换警告,而在另一种情况下却不会?

Why do I get a deprecated conversion warning with string literals in one case but not another?

我正在学习 C++。在这里显示的程序中,据我所知,str1str2 存储每个相关字符串的第一个字符的地址:

#include <iostream>
using namespace std;

int main() 
{
    char str1[]="hello";
    char *str2="world";
    cout<<str1<<endl;
    cout<<str2<<endl;
}

但是,str1 没有发出任何警告,而 str2 我收到了这个警告:

warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
     char *str2="world";

在第二种情况下而不是第一种情况下导致警告的这两个声明之间有什么不同?

问题是您正在尝试将字符串文字(类型为 const char*)转换为 char*。

写的时候

char str1[] = "hello";

你说的是 "please make me an array of chars that holds the string "hello", and please choose the size of the array str1 to be the size of the string initializing it." 这意味着 str1 最终存储了它自己唯一的字符串副本 "hello"str1 的最终类型是 char[6] - 五种用于 hello,一种用于空终止符。

当你写

char *str2 = "world";

你说的是 "please make me a pointer of type char * that points to the string literal "world"." 字符串文字 "world" 的类型为 const char[6] - 它是一个包含六个字符的数组(五个用于 hello,一个用于空终止符) ,重要的是这些字符是 const 并且不能被修改。由于您使用 char * 指针指向该数组,因此您将丢失 const 修饰符,这意味着您现在(不安全地)有一个非 const 指针指向 const 位数据。

此处情况不同的原因是,在第一种情况下,您将获得字符串 "hello"copy,因此您的数组是't const 不是问题。在第二种情况下,您没有获得 "hello" 的副本,而是获得了指向它的指针,并且由于您获得了指向它的指针,所以担心修改它可能是一个真正的问题。

换句话说,在第一种情况下,您将得到一个由六个字符组成的真实数组,其中包含 hello 的副本,因此如果您随后决定继续使用也没有问题并改变这些字符。在第二种情况下,您将获得一个指向您不应该修改的六个字符数组的指针,但您使用的是一个允许您改变内容的指针。

那么为什么 "world"const char[6]?作为对许多系统的优化,编译器只会将 "world" 的一个副本放入程序中,并使文字 "world" 的所有副本都指向内存中完全相同的字符串。这很好,只要您不更改该字符串的内容即可。 C++ 语言通过声明这些字符是 const 来强制执行此操作,因此改变它们会导致未定义的行为。在某些系统上,未定义的行为会导致 "whoa, my string literal has the wrong value in it!," 之类的事情,而在其他系统上,它可能只是段错误。