C编译器是否为用于声明数组的变量名分配内存?

时间:2013-12-09 19:08:47

标签: c arrays

让我们举一个例子: -

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;

对于变量arr,是否会有任何内存分配?

现在,如果=>

将会发生什么
p = arr;
p = &arr;
p = &arr[0];

请帮助我理解这一点。

3 个答案:

答案 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的初始元素。

完成此分配后,您可以使用arrp作为索引运算符的前缀。索引操作符实际上被定义为将指针而不是数组作为其前缀,因此arr[0]使用数组到指针转换的结果,使其与p[0]相同。

arrp仍然无法互换使用。例如,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 +1arr(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来指定任何内容(数组表达式是不可修改的左值的部分原因)。