“int *nums = {5, 2, 1, 4}"导致分段错误 [英] "int *nums = {5, 2, 1, 4}" causes a segmentation fault
问题描述
int *nums = {5, 2, 1, 4};
printf("%d\n", nums[0]);
导致段错误,而
int nums[] = {5, 2, 1, 4};
printf("%d\n", nums[0]);
没有.现在:
int *nums = {5, 2, 1, 4};
printf("%d\n", nums);
打印 5.
基于此,我推测数组初始化符号 {} 会盲目地将此数据加载到左侧的任何变量中.当它是 int[] 时,根据需要填充数组.当是int*时,指针被5填满,存放指针之后的内存位置被2、1、4填满.所以nums[0]试图deref 5,导致segfault.
Based on this, I have conjectured that the array initialization notation, {}, blindly loads this data into whatever variable is on the left. When it is int[], the array is filled up as desired. When it is int*, the pointer is filled up by 5, and the memory locations after where the pointer is stored are filled up by 2, 1, and 4. So nums[0] attempts to deref 5, causing a segfault.
如果我错了,请纠正我.如果我是对的,请详细说明,因为我不明白为什么数组初始值设定项的工作方式如此.
If I'm wrong, please correct me. And if I'm correct, please elaborate, because I don't understand why array initializers work the way they do.
推荐答案
C 中有一个(愚蠢的)规则说任何普通变量都可以用花括号括起来的初始化列表来初始化,就像它是一个数组一样.
There is a (stupid) rule in C saying that any plain variable may be initialized with a brace-enclosed initializer list, just as if it was an array.
例如你可以写int x = {0};
,它完全等价于int x = 0;
.
For example you can write int x = {0};
, which is completely equivalent to int x = 0;
.
因此,当您编写 int *nums = {5, 2, 1, 4};
时,您实际上是在为单个指针变量提供初始化列表.然而,它只是一个单一的变量,所以它只会被分配第一个值 5,列表的其余部分被忽略(实际上我不认为具有过多初始值设定项的代码甚至应该使用严格的编译器编译) - 它不会完全写入内存.代码等价于int *nums = 5;
.这意味着,nums
应该指向address 5
.
So when you write int *nums = {5, 2, 1, 4};
you are actually giving an initializer list to a single pointer variable. However, it is just one single variable so it will only get assigned the first value 5, the rest of the list is ignored (actually I don't think that code with excess initializers should even compile with a strict compiler) - it does not get written to memory at all. The code is equivalent to int *nums = 5;
. Which means, nums
should point at address 5
.
此时您应该已经收到两个编译器警告/错误:
At this point you should already have gotten two compiler warnings/errors:
- 在没有强制转换的情况下将整数分配给指针.
- 初始值设定项列表中的元素过多.
然后当然代码会崩溃并烧毁,因为 5
很可能不是一个有效地址,您可以使用 nums[0]
取消引用.
And then of course the code will crash and burn since 5
is most likely not a valid address you are allowed to dereference with nums[0]
.
附带说明,您应该使用 %p
说明符printf
指针地址,否则您将调用未定义的行为.
As a side note, you should printf
pointer addresses with the %p
specifier or otherwise you are invoking undefined behavior.
我不太确定你想在这里做什么,但如果你想设置一个指向数组的指针,你应该这样做:
I'm not quite sure what you are trying to do here, but if you want to set a pointer to point at an array, you should do:
int nums[] = {5, 2, 1, 4};
int* ptr = nums;
// or equivalent:
int* ptr = (int[]){5, 2, 1, 4};
或者如果你想创建一个指针数组:
Or if you want to create an array of pointers:
int* ptr[] = { /* whatever makes sense here */ };
<小时>
编辑
经过一些研究,我可以说多余元素初始值设定项列表"确实不是有效的 C - 它是一个 GCC 扩展.
After some research I can say that the "excess elements initializer list" is indeed not valid C - it is a GCC extension.
标准6.7.9 初始化说(强调我的):
2 任何初始值设定项都不应尝试为不属于该对象的对象提供值包含在正在初始化的实体中.
/--/
11 标量的初始化器应为单个表达式,可选用大括号括起来. 对象的初始值是表达式的(转换后);相同类型的约束和适用于简单赋值的转换,采用标量是其声明类型的非限定版本.
11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.
标量类型"是一个标准术语,指的是非数组、结构或联合类型(称为聚合类型")的单个变量.
"Scalar type" is a standard term referring to single variables that are not of array, struct or union type (those are called "aggregate type").
所以用简单的英语标准说:当你初始化一个变量时,随意在初始化表达式周围加上一些额外的大括号,只是因为你可以."
So in plain English the standard says: "when you initialize a variable, feel free to toss in some extra braces around the initializer expression, just because you can."
这篇关于“int *nums = {5, 2, 1, 4}"导致分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!