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

C将2D数组的地址分配给指针,c,arrays,pointers,C,Arrays,Pointers,我读了一些课堂讲稿,为了让指针引用2D数组,必须给它第一个元素的地址 int a[10][10]; int *p = &a[0][0]; 我从未尝试过这个方法,所以我很好奇为什么数组本身不足以分配给指针,就像我们在一维情况下所做的那样 int a[10][10]; int *p = a; 无论如何,阵列都保存在一个不间断的内存“行”中,二维阵列只有不同的类型,但结构与一维阵列相同 通过这样做 int *p = &a[0][0]; int *p = a; 我看不出我们是如何

我读了一些课堂讲稿,为了让指针引用2D数组,必须给它第一个元素的地址

int a[10][10];
int *p = &a[0][0];
我从未尝试过这个方法,所以我很好奇为什么数组本身不足以分配给指针,就像我们在一维情况下所做的那样

int a[10][10];
int *p = a;
无论如何,阵列都保存在一个不间断的内存“行”中,二维阵列只有不同的类型,但结构与一维阵列相同

通过这样做

int *p = &a[0][0];
int *p = a;
我看不出我们是如何给指针更多的信息的

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

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

您的理解很接近,区别在于类型信息。指针没有其类型。例如int*p,指针类型为int*,如int a[10][10],对应的指针类型为int*[10][10]

在您的示例中,p和do指向相同的地址,但它们是不同的类型,这在对它们执行算术运算时很重要

这里有一个例子

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

char *mychar;
short *myshort;
long *mylong;
我们知道它们分别指向内存位置1000、2000和3000

因此,如果我们写:

++mychar;

++myshort;

++mylong;
正如人们所期望的,mychar将包含值1001。但不是很明显,myshort将包含值2002,mylong将包含值3004,尽管它们每个值只增加了一次。原因是,当向指针添加一个时,指针会指向相同类型的以下元素,因此,指针所指向类型的大小(以字节为单位)会添加到指针

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

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

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

您是对的,可以将数组本身指定给指针:

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

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

首先,一些背景:

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

根据声明

int a[10][10];
表达式
a
的类型为“10元素数组的10元素数组的
int
”。除非此表达式是
sizeof
或一元
&
运算符的操作数,否则它将转换为“指向
int
的10元素数组的指针”或
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 *
而且

请注意,不同的指针类型
int(*)[10][10]
int(*)[10]
int*
不必具有相同的大小或表示形式,尽管在我熟悉的平台上是这样的

数组的第一个元素的地址与数组本身的地址相同;因此,所有
a
&a
a[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;
所有
p0
p1
p2
最初都具有相同的值,即
a
中第一个元素的地址;但是,由于指针类型不同,涉及指针算法的结果操作也会不同。表达式
p0+1
将产生下一个
int
对象的地址(
&a[0][1]
)。表达式
p1+1
将产生
int
的下一个10元素数组的地址(
&a[1][0]
)。最后,表达式
p2+1
将产生
int
的10元素数组的下一个10元素数组的地址(实际上,
&a[11][0]

注意
p1
p2
的类型;两者都不是简单的
int*
,因为用于初始化它们的表达式不是那种类型(请参阅第一个表)


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

在二维数组中,
*a
a
的结果是相同的,它们都指向这个二维数组的第一个地址

但是,如果要定义指向该数组的指针,可以使用
int(*ptr)[10]

您是对的,1D和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;
}
#包括
int main(){
INTA[10][10];
int*pa1=&a[0][0];
int*pa2=*a;
printf(“pa1是%p