C 中有一条(愚蠢的)规则,规定任何普通变量都可以使用大括号括起来的初始化列表进行初始化,就像它是一个数组一样。
例如你可以写int x = {0};
,这完全等价于int x = 0;
.
所以当你写的时候int *nums = {5, 2, 1, 4};
您实际上是为单个指针变量提供了一个初始值设定项列表。然而,它只是一个单一变量,所以它只会被分配第一个值 5,列表的其余部分被忽略(实际上我不认为具有过多初始化程序的代码甚至应该使用严格的编译器进行编译) - 它不完全被写入内存。代码相当于int *nums = 5;
。意思是,nums
应该指向address 5
.
此时您应该已经收到两个编译器警告/错误:
- 将整数分配给指针而不进行强制转换。
- 初始化列表中的元素过多。
当然,代码会崩溃并烧毁,因为5
很可能不是允许您取消引用的有效地址nums[0]
.
作为旁注,你应该printf
指针地址与%p
说明符,否则您将调用未定义的行为。
我不太确定你想在这里做什么,但如果你想设置一个指针指向数组,你应该这样做:
int nums[] = {5, 2, 1, 4};
int* ptr = nums;
// or equivalent:
int* ptr = (int[]){5, 2, 1, 4};
或者如果你想创建一个指针数组:
int* ptr[] = { /* whatever makes sense here */ };
EDIT
经过一些研究,我可以说“多余元素初始化列表”确实不是有效的 C - 它是一个海湾合作委员会扩展.
标准6.7.9 初始化说(强调我的):
2 任何初始值设定项都不得尝试为不属于该对象的对象提供值
包含在正在初始化的实体中。
/--/
11 标量的初始值设定项应为单个表达式,
可选择用大括号括起来。该对象的初始值为
表达式的(转换后);相同的类型约束和
与简单赋值一样的转换适用,采用的类型
标量是其声明类型的非限定版本。
“标量类型”是一个标准术语,指的是非数组、结构或联合类型(称为“聚合类型”)的单个变量。
因此,标准用简单的英语来说:“当你初始化一个变量时,请随意在初始化表达式周围添加一些额外的大括号,因为你可以。”