指针数组
它实际上是一个数组,只不过数组的每个元素存放的都是一个指针类型的元素,所以可以通过取两次地址来得到存放的内容,所以可以说指针数组和二级指针是有联系的,因为二级指针就是用来存放地址的。
定义int *p[3];
#include <stdio.h>
int main(){
char **argv;
char *buf[]={"aa","bb","cc"};
argv =buf;
printf("%s\n",argv[0]);
printf("%s\n",argv[1]);
printf("%s\n",argv[2]);
printf("偏移前地址:%p\n",argv);
printf("偏移后地址:%p\n",argv+1);
printf("一个指针所占的字节大小:%ld\n",sizeof(char *));
printf("%c\n",(*argv)[0]);
printf("%c\n",argv[0][0]);
return 0;
}
从这个例子我们可以看到,偏移一位后,是偏移量是8,因为指针类型在64位里就是8个字节,所以也很好的说明了,二级指针就是存放指针的指针,也是指针数组的作用,所以在c语言中main函数的第二个参数,可以写char **argv,也可以写char *argv[].
这个例子里(*argv)[0]和argv[0][0]是一样的效果,因为argv就是数组的首地址,那么取内容,就是指针数组里第一个指针成员。
数组指针
它实际上是一个指针,不过该指针是指向一个数组的,类似于结构体指针,字符指针,只不过这个是一个类型为数组的指针,它偏移一位的偏移量是定义的这个数组的大小,而二维数组一级索引偏移一位,也是偏移了一个数组的大小,所以数组指针和二维数组是有联系的。
定义int (*p)[3];
#include <stdio.h>
int main(){
int a[][3]={1,2,3,4,5,6,7,8,9};
int *p;
int (*p1)[3];
p1=a;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
printf("%d行 %d列 地址:%p\n",i,j,&a[i][j]);
}
}
printf("二维数组数组名的地址:%p\n",a);
printf("一级索引偏移一位的地址:%p\n",a+1);
printf("数组指针内的第一个数的地址:%p\n",p1[0]);
printf("数组指针偏移一位的地址:%p\n",p1+1);
return 0;
}
从这个例子我们可以看出,二维指针一级索引偏移一位和数组指针偏移一位的偏移量是一样的,都是12个位置,而一个内存地址代表一个字节(8bit)的存储空间,所以就是偏移了12个字节,,一个int型的数据是4个字节,一个数组就刚好12个字节,而又因为这里直接是让指针指向二维数组开头,所以偏移一位之后也就会指向下一行数组。