char *ch = "delhi"; // valid
int *arr = {1, 2, 3}; // invalid
int *arr = (int[3]){1, 2, 3}; // valid
为什么上述某些陈述有效而其他陈述无效?
答案 0 :(得分:6)
免责声明:我正在回答C ++的问题,我认为答案在很多方面都不适用于C.
简而言之,指针和数组是不同的东西。
在c ++中,
int *arr = {1, 2, 3};
无效,因为指针无法通过list initialization进行初始化。
int *arr = (int[3]){1, 2, 3};
有效,因为数组可以通过列表初始化进行初始化,aggregate initialization实际上将被应用于数组。对于这种情况,将构造一个临时数组,然后衰减到int*
并分配给arr
。请注意,临时变量将在语句后被销毁,因此arr
将在此之后悬空。
char *ch = "delhi";
在c ++ 11中无效,const char* ch = "delhi"
有效。 "德里"是string literal类型const char[6]
,然后衰为const char*
并分配给ch
。因为字符串文字具有静态存储持续时间,ch
不会被悬空。
请注意,它不是int
指针的特殊规则,它对char
指针也是一样的。 const char* ch1 = { 'd', 'e', 'l', 'h', 'i', '\0'};
也会失败。
答案 1 :(得分:3)
char *ch = "delhi"; // valid
这使用字符串文字。编译器生成静态c-string并将其起始地址分配给ch
。这种语法对于字符串是特殊的,并且为了避免每次都输入类似char ch[] = {'d', 'e', 'l', 'h', 'i', '\0'};
的内容而被引入。
int *arr = {1, 2, 3}; // invalid
{1, 2, 3}
是一个数组初始值设定项,或者从c ++ 11开始的std::initializer_list
。在第一种情况下,数组初始值设定项不是'数组文字'但是编译器理解并且仅适用于数组的特殊便利语法(int*
和int[]
的类型略有不同)。在c ++ 11的情况下,您根本无法从std::initializer_list<T>
转换为T*
。
int *arr = (int[3]){1, 2, 3}; // valid
在这种情况下,您告诉编译器生成临时int[3]
数组,使用列表初始化它,并将其地址分配给arr
。有效,但您应该收到一条警告,告知您正在获取临时对象的地址或类似内容。
答案的第一部分似乎暗示字符串文字和char[]
是相同的。这是无意的,希望这部分&#34;编译器生成一个静态的c-string ...&#34;在大多数情况下,第二段的评论避免了这种误解。
声明&#34; {1,2,3}是c ++ 11&#34;中的std :: initializer_list。是不正确的。 &#34; {1,2,3}&#34;是一个braced-list-initializer,它本身不是一个类型。它是一个语法元素,可以根据上下文初始化某些类型。
答案 2 :(得分:1)
免责声明:我正在回答C ++的问题 - 一些推理可能也适用于C,但我没有检查后者。
字符串文字(第一个示例的右侧)是(在c ++中)具有静态存储持续时间的const char
数组。这意味着编译器将它们放在内存中的固定位置,在整个程序执行期间保持有效。因此,您可以像任何其他数组一样将它们分配给指针(存储第一个元素的地址)。
您的特定示例在c ++ 11及更高版本中不起作用,因为ch
实际上必须是const char*
类型。在C-但是 - 据我所知 - 字符串文字是char
(非常量)类型的数组,所以你也可以在c之前将它们分配给普通的char
ptr和c ++版本。 ++ 11允许这项任务是出于嗜宿的原因。
第二行是无效的C ++代码,原因有多种: 与第一行相反,右侧不是数组,因此指针衰减的数组在这里不起作用。现在,您可以使用和初始化列表初始化指针,但仅限于
nullptr
)然而,与第一个示例相比,含义会完全不同:您不会使用初始化列表中的元素地址初始化指针,而只是使用副本
现在在第三个例子中(顺便说一下,c ++编译器会拒绝它,但是对const int*
和const int[]
是可以的))我相信你正在创建一个通过复制初始化的临时数组初始化列表的内容(整数文字),然后将其分配给指针。 Imho这个应该在声明结束时立即生成悬挂指针,但我不是百分之百确定它。