使用指针初始化常量数组

4
为什么第一行是有效的,而其他行都是无效的。我以为第一行是第二行的简写形式。
const char *c = "abc"; // Why valid?

const char *b = { 'a' , 'b', 'c', '\0' }; // invalid

const int *a = { 1, 2, 3, 0 }; // invalid
4个回答

3
这里的真正区别在于"abc"char[]类型的字符串字面量,而{'a', 'b', 'c', 0}不是。你可以轻松使用它来初始化完全不同的类型,例如:
struct s{
  char c;
  int i, j;
  float f;
} x = {'a', 'b', 'c', 0};

因此,当您编写const char *b = { 'a' , 'b', 'c', '\0' };时,编译器选择隐式转换{'a'} -> 'a'并尝试用它来初始化指针。这可能会成功或失败,具体取决于编译器和实际值。例如,许多编译器会将const char *b = { '\0' };解释为将b初始化为NULL指针,而不是像人们期望的那样为空字符串。
如果要将指针初始化为使用列表初始化创建的数组(或任何其他类型)的地址,则应明确进行强制转换:
const char *b = (const char[]){'a', 'b', 'c', 0};
const int *a = (const int[]){'a', 'b', 'c', 0};
struct s *x = &(struct s){'a', 'b', 'c', 0};

1
我相信这是正确的答案。修改我的回答可能等同于复制你的观点。因此,我删除了我的回答并点赞了这个。感谢你提出这个问题。 - Marco A.

1
在第一个情况中,您有一个字符串字面量,它是char数组,在此上下文中将转换为指向char的指针。
在接下来的两种情况中,您尝试使用列表初始化来初始化指针,这将尝试将列表的第一个元素转换为指针,从而生成警告,因为char或int都不是指针,就像这样:
const char *b = 'a' ;

如果列表中有有效的指针,那么对于第一个元素它可以正常工作,但由于您有更多的初始化程序而不是变量,因此它将是不合法的。

0

数组和指针不是同一件事。

const char *c = "abc";

用字符串常量的地址初始化指针。字符串常量存储在其他地方(不在堆栈中,通常是特殊的全局常量区域)。

const char c[] = "abc";

使用给定的字符(以给定字符串的内容)初始化字符数组。这个数组将会在堆栈上。


0

第一行是有效的,因为C标准允许创建常量字符串,因为它们的长度可以在编译时确定。

对于指针不适用相同的规则:编译器无法决定是否应该在堆中分配数组的内存(就像普通的int[]一样),还是在常规内存中,例如malloc()。

如果您将数组初始化为:

   int a[] = { 1, 2, 3, 0 };

那么它就变得有效了,因为现在编译器确信你想要一个位于堆(临时)内存中的数组,并且在你离开声明它的代码段后,它将从内存中释放。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接