二维数组的静态和动态声明之间的区别

时间:2018-10-08 21:34:45

标签: c arrays pointers

这两个是用于声明2D数组的不同程序

1)我认为它们是相同的,因为它们都是二维数组?

2)我们可以同时使用a [i] [j]和p [i] [j]访问吗?

3)为什么*aa相同而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);

   }

3 个答案:

答案 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本身就是一个指针,*pp所指向的变量的内容。它们和您执行此操作时一样不同:

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?