C 允许你创建精心定制的数据形式. 虽然我们坚持使用较简单的形式, 但是我们觉得应该指出这些可能性. 当进行一个声明时, 可以添加一个修饰符来修饰名称 (或标识符).
表 14.1 声明时可以使用的修饰符
--------------------------------------------------------------
修饰符 含义
--------------------------------------------------------------
* 表示一个指针
-------------------------------------------------------------
() 表示一个函数
--------------------------------------------------------------
[] 表示一个数组
-------------------------------------------------------------
C 允许同时使用多于 1 个的修饰符, 这就使得可以创建如下各种各样的类型:
int board[8][8]; /* int 数组的数组 */
int ** ptr; /* 指向 int 指针的指针 */
int * risks[10]; /* 具有 10 个元素的数组, 每个元素是一个指向 int 的指针 */
int (* rusks) [10]; /* 一个指针, 指向具有 10 个元素的 int 数组 */
int * oof[3][4]; /* 一个 3 x 4 的数组, 每个元素是一个指向 int 的指针 */
int (* uuf) [3][4]; /* 一个指针, 指向 3 X 4 的 int 数组 */
int (* uof[3]) [4]; /* 一个具有 3 个元素的数组, 每个元素是一个指向具有 4 个元素的 int 数组的指针 */
弄清楚这些声明的诀窍便于理解使用修饰和的顺序. 下面这些规则会让你对其有所了解:
1. 表示一个数组的 [] 和表示一个函数的 () 具有同样的优先级, 这个优先级高于间接运算符 * 的优先级. 这意味着下面的声明使得 risks 是一个指针数组, 而不是一个指向数组的指针:
int * risks[10];
2. [] 和 () 都是从左到右进行结合的. 下面的声明使 goods 是一个由 12 个具有 50 个 int 值的数组构成的数组, 而不是一个由 50 个具有 12 个 int 值的数组构成的数组:
int goods[12][50];
3. [] 和 () 具有相同的优先级, 但由于它们是从左到右结合的, 所以下面的声明在应用方括号之前先将 * 和 rusks 组合在一起. 这意味着 rusks 是一个指向具有 10 个 int 值的数组的指针:
int (* rusks) [10];
我们把这些规则应用于下面这个声明:
int * off[3][4];
[3] 具有比 * 更高的优先级, 并且根据从左到右的规则, 它的优先级比 [4] 高. 因此, oof 是一个具有 3 个元素的数组. 下面是 [4], 所以 oof 的元素是具有 4 个元素的数组. * 说明这些元素都是指针. int 完成了该描述: oof 是一个 3 个元素数组, 每个元素由 4 个指向 int 的指针组成的数组. 或者简单地说, 它是一个 3X4 的指向 int 的指针数组. 需要为 12 个指针留出存储空间.
现在来看看这个声明:
int (* uuf) [3][4];
圆括号使修饰符 * 具有最高优先级, 所以 uuf 就是一个指向 3x4 的 int 数组的指针. 需要为一个单个指针留出存储空间.
这些规则同样也产生下面的类型:
char * fump(); /* 返回指向 char 的指针的函数 */
char (* fume) (); /* 指向返回类型为 char 的函数的指针 */
char (* fume[3] ) (); /* 由 3 个指针组成的数组, 每个指针指向返回类型为 char 的函数 */
可以使用 typedef 建立一系列相关的类型:
typedef int arr5[5];
typedef arr5 * p_arr5;
typedef p_arr5 arrp10[10];
arr5 togs; /* togs 是具有 5 个元素的 int 数组 */
p_arr5 p2; /* p2 是一个指针, 指向具有 5 个元素的 int 数组 */
arrp10 ap; /* ap 是具有 10 个元素的指针数组, 每个指针指向具有 5 个元素的 int 数组 */
当把结构也带入这样的描述中, 声明的可能性真的会变得很复杂. 至于应用, 我们就不再讨论了.