让我们举一个例子: -
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
对于变量arr,是否会有任何内存分配?
现在,如果=>
将会发生什么p = arr;
p = &arr;
p = &arr[0];
请帮助我理解这一点。
答案 0 :(得分:4)
此声明:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
导致10 * sizeof (int)
个字节被分配以容纳10个元素的数组对象。 (没有为任何指针对象分配空间。)数组按指定初始化。
int *p = NULL;
创建一个指针对象并将其初始化为包含空指针值。
p = arr;
arr
是数组类型的表达式。在大多数情况下,它的值被隐式转换为指向其第一个元素的指针。因此,此赋值会导致p
指向arr
的第一个(第0个)元素; *p == 1
。
p = &arr;
这是无效的。 &arr
的类型为int(*)[10]
,或指向10 int
的数组的指针。 p
的类型为int*
。这些类型是不兼容的。任何符合要求的C编译器都必须诊断此错误。 (诊断可能是一个非致命的警告,但不要让它欺骗你;它仍然是一个错误,C标准称之为“约束违规”。)
p = &arr[0];
这与p = arr;
相同。 arr[0]
是数组的第一个(第0个)元素,int
对象,其值为1
。 &arr[0]
是int
个对象的地址,类型为char*
。因此,这也会导致p
指向数组arr
的初始元素。
完成此分配后,您可以使用arr
或p
作为索引运算符的前缀。索引操作符实际上被定义为将指针而不是数组作为其前缀,因此arr[0]
使用数组到指针转换的结果,使其与p[0]
相同。
但arr
和p
仍然无法互换使用。例如,sizeof arr
为您提供数组对象的大小(10 * sizeof (int))
,而sizeof p
为您提供指针的大小(sizeof (int*)
)。
建议阅读:comp.lang.c FAQ的第6部分。
(为了回答标题中的问题,编译器没有,或者至少不需要在运行时为数组的 name 分配内存。它不会在运行时分配3个字节的内存,因为您将数组命名为arr
,或者因为您将其命名为array_with_a_long_name
而将其命名为22个字节。它可能会出于调试目的而这样做,但随后无法访问任何此类分配的空间到你的程序。)
答案 1 :(得分:1)
arr[10]
创建10个整数的位置。
p = arr ;
p= &arr[0] ;
是一回事。
&arr
通常不是很有用。它是int (*)[10]
编译器应该抱怨分配给p
。
事实上,如果你做了一点测试并打印出这三个地址:
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
gcc最终会为这三种情况提供同样的东西。
% ./a.out
X: 7fff906b5b20 7fff906b5b20 7fff906b5b20
但是你真正看到的区别在于你是否要求每个项目+1:
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
printf("X+1: %lx %lx %lx\n", (long) (arr +1), (long) ( &arr +1) , (long) ( &arr[0] +1 )) ;
% ./a.out
X: 7fff73c105b0 7fff73c105b0 7fff73c105b0
X+1: 7fff73c105b4 7fff73c105d8 7fff73c105b4
arr +1
比arr
(int的大小)大四个字节,与&arr[0] +1
一样,但&arr +1
大40个字节,整个大小阵列。
答案 2 :(得分:0)
除了支持调试器之外,不会为变量名(数组或其他)留出存储空间。
除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化数组的字符串文字,否则表达式为“N-element array of of T
“将被转换(”衰减“)为”指向T
的指针“的表达式,该表达式的值将是数组的第一个元素的地址。
所以,考虑你的三个案例:
p = arr;
表达式arr
的类型为“10个元素数组int
”。由于它不是sizeof
或一元&
运算符的操作数,因此它将转换为“指向int
”或int *
的指针类型的表达式,并且value是数组第一个元素的地址。
p = &arr;
表达式arr
的类型为“10个元素数组int
”。由于arr
是一元&
运算符的操作数,因此不执行上述转换;相反,表达式&arr
的类型是“指向arr
的10个元素数组的指针”或int (*)[10]
。 值与上面的表达式相同(数组的地址与数组的第一个元素的地址相同),但两者的类型表达式是不同的(int *
与int (*)[10]
),并且类型对于指针算术这样的事情很重要。
p = &arr[0];
提供与p = arr;
相同的类型和结果。
对于您的阵列,存储如下:
+----+
arr[0]: | |
+----+
arr[1]: | |
+----+
... ...
+----+
arr[9]: | |
+----+
请注意,名为arr
的变量没有单独的存储空间,指向数组的开头;如上所述,从数组表达式推断出该指针值。您可以分配给arr[N]
,但没有单独的arr
来指定任何内容(数组表达式是不可修改的左值的部分原因)。