1、指针与一维数组
2、指针与二维数组
3、指针数组与数组指针
指针里面最难的一种就是指针与数组了,对于指针和二维数组来说这里面的关系比较复杂。牵涉到编译器的原理和编译过程。
1、指针与一维数组
指针是指向一个内存的地址,一维数组的数组名代表一块内存(这个数组)的首地址,和数组首元素的地址一样,但数组名不等价与首元素的地址,数组名代表一整块地址,不仅仅是一个元素。指针和数组名都和地址有关系,这两个有什么区别呢?
如果仅仅是使用上来说,数组名不能再被赋别的地址,因为它可以理解为是一个指针常量(指向地址的内容可以修改,指向的地址无法修改),也可以理解为数组名仅仅是一个标号,在编译的过程中,并没有分配内存空间,只存在于符号表里。
除了这些,正常使用时它和指针在使用上就没有区别了。(编译时,编译器不会对指针访问数组越界处理,而通过数组名越界会出错)
#include<stdio.h>
int main(void){
int a[3]={1,2,3};
int *ptr=a;
printf("a size is %d\n",sizeof(a));
printf("ptr size is %d\n",sizeof(ptr));
printf("a[0] is %d\n",*a);
printf("a[1] is %d\n",*(a+1));
printf("a[1] is %d\n",a[1]);
printf("a[1] is %d\n",*(ptr+1));
printf("a[1] is %d\n",ptr[1]);
}
总结:a作为右值时的等同于&a[0],表示数组首元素的地址,而不是数组的首地址,这仅仅是代表,并没有一个地方来存储这个地址,也就是说编译器并没有为数组a分配一块内存来存储其地址,这一点就与指针有很大的差别。但是在对数据的操作上可以认为大致等价。
2、指针与二维数组
说这个复杂,其实也不太复杂,复杂就复杂在这里有二维指针的概念。
同样的,数组名代表二维数组的首地址,是一整块内存的首地址。
访问方式可以是**p *p[i] p[i][j]三种方式这里p同样可以换成数组名
区别和上面差不多,只不过在将二维数组名赋值给指针时,不能采用**p=a
这种形式。
#include<stdio.h>
int main(void){
int a[2][2]={1,2,3,4};
//int (*ptr)[2]=a;
int *ptr[2]={a[0],a[1]};
//int **ptr=(int**)a;//有问题
printf("a size is %d\n",sizeof(a));
printf("ptr size is %d\n",sizeof(ptr));
printf("a[0] is %d\n",**a);
printf("a[1] is %d\n",**(a+1));
printf("a[1] is %d\n",*a[1]);
printf("a[1] is %d\n",**(ptr+1));
printf("a[1] is %d\n",*ptr[1]);
}
3、指针数组与数组指针
这个也是最容易混淆的概念,当面对的是二维数组是,这两个作用一样,都可以来接收二维数组。
数组指针:存放指针的数组
指针数组:指向数组的指针
#include<stdio.h>
int main(void){
int a[2][3]={1,2,3,4,5,6};
int (*ptr)[3]=a;//指针数组
//int *ptr[2]={a[0],a[1]};//数组指针
printf("a[0] is %d\n",**a);
printf("a[1] is %d\n",**(a+1));
printf("a[1] is %d\n",*a[1]);
printf("a[1] is %d\n",**(ptr+1));
printf("a[1] is %d\n",*ptr[1]);
}