在C语言中初始化字符串和数组 - 区别

4

我在尝试用C语言初始化数组和字符串的方法时,发现以下几点:

char *str = "ABCDE";

完美地初始化了字符串,没有错误或警告,但是:

int *array = {1,2,3,4,5};

我的程序提示警告并最终崩溃,这真的很困扰我,我想知道为什么这种声明对字符有效,但对整数无效...

编辑说明:我正在使用gcc编译器。


4
永远不要将字符串字面值赋值给 char* - Cat Plus Plus
@CatPlusPlus 通常来说,这是一个不好的建议。但在数十亿个程序中,这是完全可以接受的并且被广泛采用的做法。 - Jens
4
@Jens:什么?不,你不能修改字符串字面量后面的内存。这是未定义的行为(虽然几乎肯定会崩溃)。‘const’的作用是在bug发生之前捕获它。 - Cat Plus Plus
@CatPlusPlus,我们有一个误解。我的意思是将字符串字面值分配给char *是完全可以的。未定义的是修改由此指针指向的字符。你的评论很容易被误读为永远不要编写像char *ptr; ... ; ptr = "foo"这样的语句。 - Jens
2
@Jens:不,那正是我想说的。永远不要这样做,因为你在撒谎(字符串字面值不可变,而你正在使用可变类型)。我知道C程序员在类型安全方面很糟糕,但在这种情况下,你可以避免错误,所以没有理由不这样做。如果我有话语权,“char *foo =“ foo”;”无论以何种形式出现,都永远不会通过代码审查。 - Cat Plus Plus
显示剩余2条评论
2个回答

7

通过这样做,它可以处理整数:

int array[] = {1,2,3,4,5};

或者这个:
int *array = (int[]){1,2,3,4,5};

""字符串"告诉编译器实例化字符串所需的所有信息(大小,类型)(也就是一个带有NULL终止符的字节数组)。裸体的{}没有这个作用,除非你将其声明为复合文字。添加ints[]告诉编译器,初始化数据是一个整数数组。

正如Nathan在评论中指出的那样,两种语句有微妙的差别。

第一种,在堆栈上定义了一个包含5个整数的数组。这个数组可以被修改,并且在函数结束之前一直存在。

第二种情况下,1)在堆栈上定义了一个匿名数组,其中包含5个int 2)定义了一个指针“array”,指向堆栈上匿名数组的第一个元素。由于内存在堆栈上,因此不应返回该指针。此外,该数组不像字符串文字那样本质上是const。

编辑:根据评论者的指出,用复合文字替换了强制转换。

"

2
只是想补充一下,这两个语句非常不同,第一个在堆栈中创建一个数组,并将该数组复制到其中,第二个声明了一个指针在堆栈中,并将其值设置为文字数组。因此,第二个实际上应该是const int *array = (int[])... - Nathan Day
@NathanDay:你能指点我一些资源,让我了解更多你提到的那些“幕后”的事情吗? - Maputo
1
@CatPlusPlus也许你可以解释一下你认为哪里有问题,而不是发表嘲讽的评论。 - James
1
@Cheersandhth. - Alf 用gcc和clang编译并运行,正如我所解释的那样。欢迎解释和纠正。我在这里学习,就像其他人一样。 - James
+1 移除了我的踩票。我没有点赞,因为 "cast" 的解释非常误导人,并且代码目前(截至2012年)无法有效移植,因为它受到 Visual C++ 的限制。这是一个复合字面值,而不是一个转换后的大括号初始化程序。 - Cheers and hth. - Alf
显示剩余8条评论

4

字符串字面量会衰减为一个 const char 指针。 而在 C 语言中,{1,2,3,4,5} 是一个数组,不会衰减。 因此,在 C 语言中需要使用创建数组的语法,例如:

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

然后你可以指向它:
int a[] = {1,2,3,4,5} ;
int *p = a;

由于数组的名称是数组或第一个元素的地址。希望这有所帮助。

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