为什么我会在一种情况下得到一个带有字符串文字的弃用转换警告,而不是另一种情况?
我正在学习C++。在据我所知这里所示,该节目,str1
和str2
店的每一个相关的字符串的第一个字符地址:为什么我会在一种情况下得到一个带有字符串文字的弃用转换警告,而不是另一种情况?
#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";
这两个声明有什么区别,导致在第二种情况下警告,但不是第一种?
当你写
char str1[] = "hello";
你说:“请让我的char
s表示包含字符串"hello"
数组,请选择该阵列str1
的尺寸为字符串的大小对其进行初始化“。这意味着str1
最终会存储自己的字符串"hello"
的唯一副本。 str1
的最终类型是char[6]
- 对于hello
有五个,对于空终止符有一个。
当你写
char *str2 = "world";
你说:“请让我char *
类型的指针指向字符串字面"world"
。”字符串文字"world"
的类型为const char[6]
- 它是一个由6个字符组成的数组(其中hello
五个,一个用于空终止符),重要的是那些字符是const
,并且无法修改。由于您使用char *
指针指向该阵列,因此您将丢失const
修饰符,这意味着您现在(不安全)的指针具有指向const
位数据的非const
指针。
的原因,事情在这里不同的是,在第一种情况下,你所得到的字符串"hello"
的副本,所以实际上你的阵列是不是const
是没有问题的。在第二种情况下,您没有获得"hello"
的副本,而是获取指向它的指针,并且由于您正在获得指向它的指针,因此修改它可能是一个真正的问题。
换句话说,在第一种情况下,你会得到一个由6个字符组成的诚实善良数组,其中包含hello
的副本,所以如果您决定去修改这些字符,则没有任何问题。在第二种情况下,你得到一个指向一个你不应该修改的六个字符的数组,但是你使用了一个允许你改变事物的指针。
那么为什么"world"
是const char[6]
?作为许多系统的优化,编译器只会将"world"
的一个副本放入程序中,并且将文字"world"
的所有副本指向内存中完全相同的字符串。这很好,只要你不改变那个字符串的内容。 C++语言通过说这些字符是const
来强制执行此操作,所以对它们进行变异会导致未定义的行为。在某些系统中,这种未定义的行为会导致诸如“whoa,我的字符串文字具有错误值!”等情况,而在其他系统中,它可能只是段错误。
你好,这是一个非常好的答案。我可以知道“你好”和“世界”都被视为字符串文字吗?或者只有“世界”被认为是字符串文字(bcz它被分配给char *)? – Bahubali
“hello”和“world”都是字符串文字。这里的区别出现在你分配这些文字的基础上。在第一种情况下,赋值被视为数组初始化,所以创建了一个文字副本。第二,它是指针初始化,所以没有复制。 – templatetypedef
“str1和str2应存储字符串的第一个字符的地址”。这不是真的。 'str1'存储整个字符串本身的副本。它不存储任何“地址”。另一方面,'str2'确实存储地址。 – AnT
HI ANT,如果副本存储在str1中,那么将存储另一个“hello”副本?如果我们修改str1复制str str [0] ='H',这个改变会影响另一个副本吗? – Bahubali
最初的''hello''存储在静态和不可修改的内存中。当你执行'str [0] ='H''时,你修改存储在'str1'中的副本。原稿保持不变。 – AnT