C将2D数组的地址分配给指针
我读了一些课堂讲稿,为了让指针引用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; 我看不出我们是如何
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