这两个是用于声明2D数组的不同程序
1)我认为它们是相同的,因为它们都是二维数组?
2)我们可以同时使用a [i] [j]和p [i] [j]访问吗?
3)为什么*a
或a
相同而p
或*p
不同
#include<stdio.h>
#include<stdlib.h>
int main(){
int a[100][100];
printf("%d\n",a);
printf("%d\n",*a);
int **p=malloc(sizeof(int*)*100);
for(int i=0;i<100;i++){
p[i]=malloc(sizeof(int)*100);
}
printf("%d",p);
printf("%d",*p);
}
答案 0 :(得分:3)
最大的区别在于,对于a[100][100]
,编译器知道数组的完整大小,并在堆栈(如您的情况)或静态区域中分配连续的内存区域。访问数组元素时,编译器可以根据数组尺寸自由计算其地址,并使用单个引用对其进行访问。像这样
[0,0][0,1][0,2]...[0,99][1,0][1,1][1,2]...[99,0]...[99,99]
+-------0------...-----+----- 1 -------...+----- 99 -----+
在使用动态分配的情况下,仅针对数组的单个维度连续分配内存。因此,您分配了100个指针,每个指针都指向一个一维整数数组。这些阵列可以放置在任意存储位置。因此,在这种情况下,编译器必须至少进行两次引用,使用第一个索引获取指向第二个数组的指针,而不是使用第二个索引获取第二个数组中的元素。
pointers[index0] : [0][1][2]..[99]
/ | \
/ | |
V V V
[0] [0] [0]
[1] [1] [1]
... ... ...
关于a
和*a
的一些补充。在“ c”中,当在类似上下文的指针中使用数组名称时,它将被解释为数组的地址。因此,在printf中,a
指向二维数组的开头。出于相同原因,*a
应该为您提供第一列的地址。在这种情况下,它与开始或数组相同。 **a
会将您指向第一个数组元素a[0][0]
。顺便说一句,最好在此处使用%p
代替指针使用%d
。
您可以看到,对于动态数组p
,您可以得到指针数组的地址,而*p
是否为您的第一个元素p[0]
的值是:指向列的指针。地址肯定不同。
但是在两种情况下,您都可以使用a[i][j]
和p[i][j]
访问数组元素。
答案 1 :(得分:2)
它们不一样。第一个(int a[100][100]
)是作为复合对象的单个变量。另一个(int **p
)是数组的集合,您将这些数组用作矩阵的数据结构。
如果要在动态存储中拥有实际的2D阵列,请按以下步骤操作:
#include <stdlib.h>
int main()
{
int (*m)[100][100];
m = malloc(sizeof *m);
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
(*m)[i][j] = 0;
}
当然,语法有点怪异,并且您宁愿使用具有可变列数和行数的动态矩阵,这就是为什么您希望声明由int **p
指向的矩阵的原因。
a
和*a
给出相同输出的原因是因为它们都衰减到指向a
第一个元素a[0][0]
的指针。另一方面,p
本身就是一个指针,*p
是p
所指向的变量的内容。它们和您执行此操作时一样不同:
int d = 0;
int *p = &d;
printf("%p\n", p);
printf("%d\n", *p);
现在回到您的int **p
。
是的,您可以通过双重索引访问int a[][100]
和int **p
。但是,编译器对待a[i][j]
和p[i][j]
的方式存在根本差异。
在a[i][j]
中,每个a[i]
是100个整数对象的数组。因此,为了访问第i
个元素,然后访问第j
个元素,编译器必须从i*100+j
访问第a[0][0]
个元素。可以使用索引算法在一个步骤中执行此访问。
在v[i][j]
中,每个v[i]
是一个指针,可以指向内存中彼此远离的对象。为了访问元素v[i][j]
,编译器必须首先跟随p
到数组*p
,然后在该数组中找到第i
个元素,该元素是一个指针到数组p[i]
中。然后使用一些指针算法,将找到此数组的第j
个元素。
答案 2 :(得分:-2)
a
是内存中数组的地址,其值取决于编译器和操作系统布局内存的方式。 *a
是该位置在内存中的值,再次取决于您的操作系统,该值是随机的或设置为某个预定值。对于p
和*p
为便于调试,大多数操作系统将内存设置为某些有意的固定值。 Unix通常将malloc()内存设置为零。 Windows根据内存分配方式具有一系列默认内容,请参见:When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?