常见的复杂声明主要集中在指针

一、指针与数组

1、数组指针(数组的指针)

  1. //数组的指针 (数组指针)
  2. int (*risk)[10]; //一个指针,该指针指向一个元素为10个int类型的数组

2、指针数组(指针的数组)

  1. //指针的数组 (指针数组)
  2. int * risk[10]; //一个内含10个元素的数组,数组的元素是指针
  1. int board[8][8];
  2. //二维数组,声明一个内含int数组的数组
  3. int **ptr;
  4. //一个指向指针的指针,被指向的指针指向int类型数据
  5. int *risk[10]; //指针的数组 (指针数组)
  6. //一个内含10个元素的数组,数组的元素是指针
  7. int (*risk)[10]; //数组的指针 (数组指针)
  8. //一个指针,该指针指向一个元素为10个int类型的数组
  9. int *oof[3][4]; //指针的二维数组
  10. //一个二维数组,该数组的每个元素是一个int类型的指针
  11. int (*oof)[3][4]; //二维数组的指针
  12. //一个指针,该指针指向一个3*4的二维数组
  13. int (*uof[3])[4]; //一维数组的指针的数组
  14. //一个数组,该数组有3个元素,每个元素是指向一个有4个int类型元素的数组的指针

理解以上的声明,关键是理解 *、( )、[ ]的优先级。有以下规则

  • 数组名后面的 [ ] 和函数名后面的()具有相同的优先级,他们比 *(解引用运算符)的优先级高

    1. int * risk[10];
    2. //根据[]的优先级更高,所以首先是有10个元素的数组,然后每个元素是一个int 类型类型的指针
  • ( ) 与 [ ] 的优先级相同,所以都是从左往右结合

    1. int (*risk)[10];
    2. //从左往右,首先是一个指针,该指针指向一个元素为10个int类型的数组
  • ( )与 [ ] 从左往右结合

    1. int board[10][8];
    2. //二维数组,是一个由10个内含8个int类型的值组成的二维数组,
    3. //而不是一个由8个内含10个int类型的值组成的二维数组

    二、指针与函数

    ```c char *fump(int);
    //一个函数,返回字符指针的函数

char (*frump)(int);
//一个指向函数的指针,该函数的返回值是char类型,参数是一个 int类型的参数

char (*frump[3])(int); //一个内含3个元素的数组,每个元素是指向函数的指针,函数的返回值是char类型,参数是一个 int类型的参数

char (frump[3])(int); //一个内含3个元素的数组,每个元素是指向函数的指针,函数的返回值是char类型指针,参数是一个 int类型的参数

char ((x(int))[3])(int);
//一个函数,返回的是一个指针,指针指向内含三个元素的一维数组,其数组的元素是指向函数的指针,指针指向的函数返回值是char类型,参数是int类型

char ((x[3])(int))[5];
//一个内含3个元素数组,每个元素是指向函数的指针,函数的返回值是一个指针,指针指向有5个char类型元素的一维数组

  1. <a name="oB4nv"></a>
  2. #### 需要注意一些陷阱:(非法的声明)
  3. <a name="MwO4r"></a>
  4. ##### 陷阱1
  5. ```c
  6. //非法版本
  7. char fun(int)[N];
  8. //按照运算优先级,fun是一个函数,返回值是一个有N个元素的一维数组;这里的陷阱是函数只能返回标量值,不能返回数组。
  9. //正确版本
  10. char (*fun(int))[N];
  11. //这样就对了,一个函数,返回的是一个指针,该指针指向一个内含N个元素的一维数组;

陷阱2
  1. //非法版本
  2. char fun[N](int);
  3. //按照运算优先级,是一个数组,数组的元素是函数;这显然不对,函数的长度不太可能长度一致;
  4. //正确版本
  5. char (*fun[N])(int);
  6. /一个数组,元素是指针,指向一个返回值是char的函数

三、常量指针与指针常量

  1. const int *p //常量指针,指向常量的指针。即p指向的内存可以变,p指向的数值内容不可变
  2. int const *p //同上
  3. int* const p //指针常量,本质是一个常量,而用指针修饰它。 p指向的内存不可以变,但是p
  4. 存位置的数值可以变
  5. const int* const p;//指向常量的常量指针。即p指向的内存和数值都不可变

总结

根据运算优先级,确定声明的基础类型(最先开始的“运算”)。