C将2D数组的地址分配给指针

时间:2014-02-28 21:06:49

标签: c arrays pointers

我正在阅读一些讲义,为了使指针引用2D数组,必须给它第一个元素的地址。

int a[10][10];
int *p = &a[0][0];

我从来没有尝试过这个,所以我很好奇为什么不能将数组本身分配给指针,就像我们在一维情况下那样。

int a[10][10];
int *p = a;

无论如何,数组都保存在不间断的“内存”行中,而2D数组只有不同的类型,但结构与1D数组相同。

通过这样做

int *p = &a[0][0];

我没有看到我们如何给指针提供更多信息而不是通过这样做

int *p = a;

或许所有数组无论维数多少都有相同的类型,唯一的区别是多维数组在第一个元素之前存储额外的维度,我们需要跳过那些记住数组维度大小的内存空间?

5 个答案:

答案 0 :(得分:2)

首先,一些背景知识:

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,表达式为类型“{元素数组T”将被转换(“衰减”)为“指向T的指针”类型的表达式,表达式的值将是第一个元素的地址数组。

鉴于声明

int a[10][10];
表达式 a具有“10元素数组int的10元素数组”。除非此表达式是sizeof或一元&运算符的操作数,否则它将转换为“指向int的10个元素数组的指针”或{{1 }}。

鉴于该声明,以下所有情况均属实:

int (*)[10]

此外,

    Expression    Type                Decays to
    ----------    ----                ---------
             a    int [10][10]        int (*)[10]      
            &a    int (*)[10][10]     
            *a    int [10]            int *
          a[i]    int [10]            int *
         &a[i]    int (*)[10]         
         *a[i]    int          
       a[i][j]    int
      &a[i][j]    int *

请注意,不同的指针类型 sizeof a == sizeof (int) * 10 * 10 sizeof &a == sizeof (int (*)[10][10]) sizeof *a == sizeof (int) * 10 sizeof a[i] == sizeof (int) * 10 sizeof &a[i] == sizeof (int (*)[10] ) sizeof *a[i] == sizeif (int) sizeof a[i][j] == sizeof (int) sizeof &a[i][j] == sizeof (int *) int (*)[10][10]int (*)[10]不必具有相同的大小或具有相同的表示形式,尽管在我熟悉的平台上与他们一起。

数组的第一个元素的地址与数组本身的地址相同;因此,int *a&aa[0]&a[0]的所有内容都会产生相同的,但类型会有所不同(如上表所示)。

因此,假设我们添加以下声明:

&a[0][0]

int *p0 = &a[0][0]; // equivalent to int *p0 = a[0]; int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a; int (*p2)[10][10] = &a; p0p1的所有内容最初都具有相同的值,即p2中第一个元素的地址;但是,由于指针类型不同,涉及指针运算的结果操作会有所不同。表达式a将生成下一个p0 + 1对象(int)的地址。表达式&a[0][1]将生成p1 + 1int)的下一个 10元素数组的地址。最后,表达式&a[1][0]将生成p2 + 1的10个元素数组的下一个 10个元素数组的地址(实际上,int)。

请注意&a[11][0]p1的类型;既不是简单的p2,因为用于初始化它们的表达式不是那种类型(参见第一个表)。

注意模式;对于数组类型,表达式越简单,相应类型就越复杂。表达式int *不引用单个a对象;它指的是一个10x10的int个对象数组,因此当它出现在表达式中时,它被视为指向整数数组的指针,而不是指向单个整数的指针。

答案 1 :(得分:1)

编译器知道“a”是指向十个整数的指针。如果未声明维度,则编译器会将新指针视为指向未知数量的整数的指针。这将适用于您的情况,但它会生成编译器警告,因为编译器将它们视为不兼容的指针。您尝试执行的操作的语法(不生成编译器警告)是:

int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);

这很重要的一个原因是指针算术:

p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes

答案 2 :(得分:0)

你的理解很接近,不同的是类型信息。指针确实有它的类型。例如int * p,指针类型是int *,如int a [10] [10],相应的指针类型是int * [10] [10]。

在你的例子中,p和a do指向同一个地址,但它们是不同的类型,这对它们执行算术运算很重要。

以下是此URL

的示例

现在假设我们定义了三个指针:

char *mychar;
short *myshort;
long *mylong;

我们知道它们分别指向内存位置1000,2000和3000。

因此,如果我们写:

++mychar;

++myshort;

++mylong;
正如人们所预料的那样, mychar将包含值1001.但不是那么明显,myshort将包含值2002,而mylong将包含3004,即使它们每个只增加一次。原因是,当向指针添加一个指针时,指针指向相同类型的后续元素,因此,指向它的类型的字节大小将添加到指针。

答案 3 :(得分:0)

你是对的,你可以将数组本身分配给指针:

int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};

int *p, *q, *r, *s;

p = &a[0][0];   
q = a;      // what you are saying  

r = &b[0][0][0];    
s = b;      // what you are saying


printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);

printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);

输出是:

p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8

无论矩阵的大小如何,它们都指向相同的地址。所以,你说的是对的。

答案 4 :(得分:0)

在2D数组中,*aa的结果是相同的,它们都指向这个2D数组的第一个地址!

但是如果你想定义一个指向这个数组的指针,你可以使用int (*ptr)[10]作为例子。

你是对的,1D和2D共享相同的结构,但2D对上面的指针有一些额外的操作。

总而言之,在2D数组中,a*a&a[0][0]会打印相同的地址,但它们的用法可能会有所不同。

像这样:

#include<stdio.h>

int main() {
  int a[10][10];
  int *pa1 = &a[0][0];
  int *pa2 = *a;
  printf("pa1 is %p\n", pa1);
  printf("pa2 is %p\n", pa2);
  printf("Address of a is %p\n", a);

  // pointer to array
  int (*pa3)[10];
  pa3 = a;
  printf("pa3 is %p\n", pa3);

  return 0;
}

他们打印相同的地址。