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



让我们举个例子:--

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 个(元素,一个值为 1int 对象。 &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 节。

(为了回答标题中的问题,编译器不会或至少不需要在运行时为数组名称分配内存。它不会在运行时分配 3 字节的内存,因为您将数组命名为 arr ,也不会分配 22 字节的内存,因为您将其命名为 array_with_a_long_name 。它可能出于调试目的这样做,但程序无法访问任何此类分配的空间。

>arr[10]创建 10 个整数的位置。

p = arr ;
p= &arr[0] ;

是一回事。

&arr通常不是有用的东西。 这是编译器应该抱怨分配给pint (*)[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 +1arr 大四个字节(整数的大小(,就像 &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可以分配任何内容(数组表达式是不可修改的左值的部分原因(。

最新更新