我正在阅读一些讲义,为了使指针引用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;
或许所有数组无论维数多少都有相同的类型,唯一的区别是多维数组在第一个元素之前存储额外的维度,我们需要跳过那些记住数组维度大小的内存空间?
答案 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
,&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
的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数组中,*a
和a
的结果是相同的,它们都指向这个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;
}
他们打印相同的地址。