让我们举个例子:--
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
对于变量arr,是否有任何内存分配?
现在,如果=>会发生什么
p = arr;
p = &arr;
p = &arr[0];
请帮助我理解这一点。
此声明:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
导致分配 10 * sizeof (int)
个字节来保存 10 个元素的数组对象。(未为任何指针对象分配空间。 数组按指定初始化。
int *p = NULL;
创建单个指针对象并将其初始化为包含 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 个(元素,一个值为 1
的 int
对象。 &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 节。
(为了回答标题中的问题,编译器不会或至少不需要在运行时为数组名称分配内存。它不会在运行时分配 3 字节的内存,因为您将数组命名为 arr
,也不会分配 22 字节的内存,因为您将其命名为 array_with_a_long_name
。它可能出于调试目的这样做,但程序无法访问任何此类分配的空间。
>arr[10]
创建 10 个整数的位置。
p = arr ;
p= &arr[0] ;
是一回事。
&arr
通常不是有用的东西。 这是编译器应该抱怨分配给p
的int (*)[10]
。
事实上,如果你做一点测试并打印出这三个地址:
printf("X: %lx %lx %lxn", (long) arr, (long) &arr, (long) &arr[0]) ;
GCC 最终会为所有三种情况提供相同的东西。
% ./a.out
X: 7fff906b5b20 7fff906b5b20 7fff906b5b20
但是,如果您要求每个项目+1,您真正可以看到差异的地方:
printf("X: %lx %lx %lxn", (long) arr, (long) &arr, (long) &arr[0]) ;
printf("X+1: %lx %lx %lxn", (long) (arr +1), (long) ( &arr +1) , (long) ( &arr[0] +1 )) ;
% ./a.out
X: 7fff73c105b0 7fff73c105b0 7fff73c105b0
X+1: 7fff73c105b4 7fff73c105d8 7fff73c105b4
arr +1
比 arr
大四个字节(整数的大小(,就像 &arr[0] +1
一样,但&arr +1
比整个数组的大小大四十个字节。
存储不留给变量名(数组或其他(,除非支持调试器。
除非它是sizeof
或一元&
运算符的操作数,或者字符串文本用于初始化声明中的数组,否则类型为"T
的 N 元素数组"的表达式将被转换("衰减"(为"指向T
的指针"类型的表达式,并且此表达式的值将是数组第一个元素的地址。
所以,以你的三个案例为例:
p = arr;
表达式 arr
的类型为 "10 元素数组的 int
"。 由于它不是sizeof
或一元&
运算符的操作数,因此它被转换为类型为"指向int
的指针"或int *
的表达式,其值是数组第一个元素的地址。
p = &arr;
表达式arr
的类型为"10 元素数组int
"。 由于arr
是一元运算符&
的操作数,因此不执行上述转换;相反,表达式&arr
的类型是"指向 10 个元素的 arr
数组",或 int (*)[10]
。 该值与上述表达式相同(数组的地址与数组第一个元素的地址相同(,但两个表达式的类型不同(int *
vs. int (*)[10]
(,类型对于指针算术之类的东西很重要。
p = &arr[0];
给出与 p = arr;
相同的类型和结果。
对于您的阵列,存储按如下方式留出:
+----+
arr[0]: | |
+----+
arr[1]: | |
+----+
... ...
+----+
arr[9]: | |
+----+
请注意,指向数组开头的名为 arr
的变量没有单独的存储;如上所述,该指针值是从数组表达式推断出来的。 您可以分配给arr[N]
,但没有单独的arr
可以分配任何内容(数组表达式是不可修改的左值的部分原因(。