我只是想了解如何实现2D数组以及如何进行内存分配。所以我在给定的c程序中有一些疑问,为什么a和* a给出相同的地址。
#include<stdio.h>
main()
{
int i,j;
int a[3][3]={1,2,3,4,5,6,7,8,9};
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%d\t",*(*(a+i)+j));
}
printf("\n");
}
printf("%d\n",a);
printf("%d\n",a[0]+1);
printf("%d\n",a[0][0]);
printf("%d\n",a+1);
printf("%d\n",*a);
}
答案 0 :(得分:3)
2D阵列与第一个1D阵列位于同一地址,而第一个1D阵列又与第一个元素位于同一地址。那就是它,没有更多的东西。
答案 1 :(得分:1)
实际上,数组是内存的范围。
在表达式中,数组指示符将转换为指向其第一个元素的指针。
类型为&a
的表达式int (*)[3][3]
给出了数组a
存在的相同范围的地址。在这种情况下,数组a
占用的内存可以通过以下方式解释
int b[1][3][3]= { { {1,2,3 } , { 4,5,6 }, { 7,8,9 } } };
并且表达式中使用的数组指示符b
将转换为地址int ( * )[3][3]
类型&a
的第一个元素。
因此表达式
&a[0][0]
a[0]
a
&a
产生的值与数组占用范围的地址相同。
考虑到要输出指针,您应该使用转化说明符p
而不是d
。
答案 2 :(得分:1)
首先,您不应使用%d
来打印指针的地址,而应使用%p
。 %d
适用于可能适合或不适合表示地址的有符号整数,具体取决于实现。接下来,您将在C标记wiki的其他answer中找到有趣的参考资料。
现在直接回答。 int a[3][3];
声明一个由3个整数组成的3个数组的数组。所以a[0]
(或*a
)是三个元素的第一个数组。
在printf("%p\n", *a);
数组*a
decays中指向其第一个元素的指针,即&a[0][0]
,换句话说,你得到数组开头的地址。 / p>
在printf("%p\n", a);
中,数组a
也会衰减到指向其第一个元素&a[0]
的指针。这里再次获得数组开头的地址,这就是打印值相同的原因。
但即使它们指向相同的地址,&a[0]
和&a[0][0]
也是指向不同类型的指针:第一个指向3个整数的数组,而第二个指向整数。同样,&a
仍将指向相同的地址,但仍然指向另一个类型和3个数组的数组到3个整数。
由于对象的地址是其第一个字节的地址,(char *) a
,(char *) *a
和(char *) &a
都是相等的,并且是指向数组第一个字节的char指针。这是合法的,因为C语言指定可以将指向对象的指针转换为指向对象的第一个字节的char的指针。但是不允许将a
传递给期望int *
的函数,如果你这样做,正确的编译器应该发出不同间接级别的警告。
答案 3 :(得分:1)
理解2D阵列的直观方式就是这样......
a --> a[0] --> [1,2,3]
a[1] --> [4,5,6]
a[2] --> [7,8,9]
a [0],a [1],a [2]是逻辑表示而不是实际存储器。
so a[0] = a + 0*[bytes occupied by one row],
a[1] = a + 1*[bytes occupied by one row],
a[2] = a + 2*[bytes occupied by one row]
因此*a => a[0] => a
请注意,即使地址相同,&#34;类型&#34;当我们调用a
vs a[0]
或*a
时,指针会发生变化。这可以通过(a + 1)和(a [0] +1)的打印输出轻松看出。