请看下面2个表达式
int *p[3];
int (*p)[3];
前面是指针数组,后面是数组指针
一张图你就懂了
int *p[3]
是这样看待的:
p[3]
是第1部分,这显然是个数组,于是编译器为你分配一块内存,这块内存有3个坑,就是可以放3个变量。
int*
是第2部分,他表明刚才提到的3个坑里放的变量是int *
类型,即是指向int类型的指针,综上是指针数组。
int (*p)[3]
是这样看待的:
(*p)
是第1部分,这明显是一个指针变量,于是编译器为你分配一块内存,这个内存放着指针变量p。
int [3]
是第2部分,这是一个int [3]
类型变量,即这是一个能存放3个int类型变量的数组,而p是指向这个数组的指针,综上是数组指针。
为什么能这样分成第1部分、第2部分?请看下面这张表
可以看到()
的优先级是比*
高的,[]
优先级最高,()
第二,所以才能这样分成2部分看待。
讲到数组就补充下面知识点,看下图:
#include "stdio.h"
/*
1.直接对数组取址,代表整个数组地址&a
2.数组名代表首元素地址 a == &a[0]
*/
int main()
{
char str1[]="abc";
char str2[]={'a','b','c'}; //相对于str1少'\0'
char str3[]={"abc"}; //和str1等价
char str4[]={'a','b','c','\0'}; //和str1等价
int a[3];
printf("str1 sizeof %d\n",sizeof(str1));
printf("str2 sizeof %d\n",sizeof(str2));
printf("str3 sizeof %d\n",sizeof(str3));
printf("str4 sizeof %d\n",sizeof(str4));
printf("a %x\n",a);
printf("a+1 %x\n",a+1);
printf("&a[0] %x\n",&a[0]);
printf("&a[0]+1 %x\n",&a[0]+1);
printf("&a %x\n",&a);
printf("&a+1 %x\n",&a+1);
}
gcc 编译出如下结果
再看下面复杂声明:
void *(*a[3])(int b);
分析:
查看上表,[]
比*
优先级高,所以a
先和[]
结合,这是第1部分,所以他本质是数组,有3个坑。
再和*
结合,声明了指针变量,就是说坑里放的是指针变量。
再看外层,坑里的指针变量指向了长成void * (f)(int b)
这个样子的函数
综上,这是函数指针数组
二维数组指针
int a[4][5];
int (*p)[5] = a;
这里定义了一个二维数组a,而p是指向a的指针,把p叫做指向a的二维数组指针
准确来说p是指向包含5个int元素的一维数组,此时p的增加、减少是以它所指向的一维数组长度为单位。如下程序证明
#include <stdio.h>
int main()
{
int*q=NULL;
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
int (*p)[4] = a;
printf("1-%d\n", sizeof(*(p+1)));
printf("2-%d\n", sizeof(int));
printf("3-%d\n", sizeof(*(p+1)+0));
printf("4-%d\n", sizeof(q));
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
printf("%d ",*(*(p+i)+j));
printf("\n");
}
printf("\n");
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
printf("%d ",a[i][j]);
printf("\n");
}
return 0;
}
结果
上面程序是在64位系统运行的,从4可以看出一个指针变量占用8字节,int类型占用4字节,
从sizeof(*(p+1))=16
,可见取到的是一行内容,因为int是4字节,一行有4个int类型,p+1指向下一行,p-1指向上一行
但是sizeof(*(p+1)+0)
为什么为8呢,这里 *(p+1)
表示第 1 行第 0 个元素的地址,加0,就是再偏移0单位,明显这里是地址,不再是一行内容,所以当然sizeof为8。
所以:
*(p+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个元素的地址,因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;就像一维数组的名字,在定义时或者和sizeof、& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。