小兔网

1.9.17 只需一招,彻底攻克C语言指针,再复杂的指针都不怕

规则

  • ++从名字开始,关键定义都是普通的定义格式,只是定义格式缺少的部分被层层嵌套++。

    • 指针:int *p
    • 数组: int arr[10]
    • 函数指针: int (* p)(int)
    • example: int (*p3)[6];
      • (*p3): 定义p3指针,但不知道指针类型
      • int (*p3)[6]:指针类型为 int [6]的数组,所以p3指针指向一个6个元素的数组
    • example:char *(* c[10])(int **p);
      • (* c[10]) : 定义10个元素为指针的数组,指针类型未知。
      • char *(* c[10])(int **p);:该指针类型为char *(* p1)(int **p);
    • example
      1
      2
      //定义一个含4个元素数组的指针,每个元素为 函数的指针,该函数参数为 一个含10个元素的数组的引用 返回值为 含10个元素的数组的指针
      int (*(*getCA[4])(int(&)[10]))[10];
  • C语言标准规定,对于一个符号的定义,编译器总是从它的名字开始读取,然后按照优先级顺序依次解析。从名字开始,不是从开头也不是从末尾,这是理解复杂指针的关键!

  • 它们的优先级从高到低依次是:() [] *(右结合性)

    • 前缀递增递减++p*优先级相同,从右到左;
    • 后缀递增递减p++比前缀++p优先级高,从左到右。
  • 定义中被括号( )括起来的那部分。

  • 后缀操作符:括号( )表示这是一个函数,方括号[ ]表示这是一个数组。

  • 前缀操作符:星号*表示“指向xxx的指针”。

    例子

1
2
3
4
int *p1[6]; //指针数组
int *(p2[6]); //指针数组,和上面的形式等价
int (*p3)[6]; //二维数组指针
int (*p4)(int, int); //函数指针

例子详解

1
2
char *(* c[10])(int **p);
int (*(*(*pfunc)(int *))[5])(int *);
  • char *(* c[10])(int **p);

    1. (* c[10]) 指针数组,数组的每个元素是指针,指针类型未知

      [ ]的优先级高于 *,编译器先解析c[10],c 首先是一个数组,它前面的*表明每个数组元素都是一个指针,只是还不知道指向什么类型的数据。整体上来看,(* c[10])说明 c 是一个指针数组,只是指针指向的数据类型尚未确定。

    2. (int **p) :( )说明是一个函数,int **p是函数参数。

      跳出括号,根据优先级规则(() 的优先级高于 *)应该先看右边(红色粗体):

    3. char *是函数的返回值类型。

  • int (*(*(*pfunc)(int *))[5])(int *)

    1. (*pfunc) 一个指针
    2. (*(*pfunc)(int *)) :根据优先级规则应该先看右边的(int *),它表明这是一个函数,int *是参数列表。再看左边的*, ==它表明函数的返回值是一个指针,只是指针指向的数据类型尚未确定==++(下一步就是定义函数的返回值)++。
    3. 由第二步可知,它表明 pfunc 是一个指向函数的指针,现在函数的参数列表确定了,也知道返回值是一个指针了(只是不知道它指向什么类型的数据)
    4. (*(*(*pfunc)(int *))[5]):[ ] 的优先级高于 *,先看右边,[5] 表示这是一个数组,再看左边,* 表示数组的每个元素都是指针。也就是说,* [5] 是一个指针数组,函数返回的指针就指向这样一个数组。
    5. 指针数组中的指针指向原型为int func(int *);的函数。
    6. 将上面的三部分合起来就是:pfunc 是一个函数指针(蓝色部分),++该函数的返回值是一个指针,它指向一个指针数组(红色部分)++,指针数组中的指针指向原型为int func(int *);的函数(橘黄色部分)。