C允许用户自定义数据形式,虽然我们常用的是一些简单的形式,但根据需要也会使用到一些复杂的形式。像在使用更高级的指针类型中,就用到一些高级声明。
以下列举了常用了一些高级声明,在文章后面对其每一个都有详细说明。
int f; //声明一个整型变量
int *f; //声明一个指向整型的指针
int f(); //声明一个函数,返回值是一个整型值
int *f(); //声明一个指针函数,返回值是一个整型指针
int (*f)(); //声明一个函数指针,返回值是一个整型值
int *(*f)(); //声明一个函数指针,返回值是一个整型指针
int f[10]; //声明一个数组,元素类型是10个整型数据
int *f[10]; //声明一个数组,元素类型是指向整型的指针
int f()[]; //非法声明,f是一个函数,返回值是一个整型数组
int f[](); //非法声明,f是一个数组,元素类型是返回值为整型的函数
int (*f[])(); //声明f是一个数组,数组元素的类型是函数指针,它所指向的函数的返回值是一个整型值
int *(*f[])(); //声明一个指针数组,指针所指向的类型是返回值为整型指针的函数
int (*f)(int,float); //声明一个函数指针,它所指向的函数接受两个参数,一个整型值,一个浮点型值,并返回一个整型值
int *(*g[])(int,float); //声明一个指针数组,数组元素是一个函数指针,它所指向的函数接受两个参数,一个整型值,一个浮点型值,并返回一个整型指针
1.高级声明的符号说明
在一些高级声明中,常包含如下符号:
符号 | 符号名称 | 含义 |
* | 间接访问操作符 | 表示一个指针 |
( ) | 函数调用操作符 | 表示一个函数 |
[ ] | 数组下标引用操作符 | 表示一个数组 |
关于*、( )、[ ]的优先级由一下几条规则:
(1)数组下标引用操作符[ ]和函数调用操作符( )具有相同的优先级。它们比间接访问操作符*的优先级高。
//下面声明的f是一个指针数组,而不是指向数组的指针(此处没看懂没关系,后面有详解)
int *f[10];
(2)[ ]和( )优先级相同,都是从左往右结合,如果想要*的优先级高于这两个符号优先级,需要在使用*的地方添加括号。
//此处声明f是一个指向数组的指针,该数组包含10个int类型的元素
int (*f)[10];
2.举例说明
(1)变量
先举一个简单例子进行说明。
int f; //声明一个整型变量
int *f; //声明一个指向整型的指针
在上面两个声明中,第2个声明是如何工作的:把表达式*f声明为了一个整数。据此,我们可以推断出f是个指向整型的指针。
(2)函数
int f(); //声明一个函数,返回值是一个整型值
int *f(); //声明一个指针函数,返回值是一个整型指针
int (*f)(); //声明一个函数指针,返回值是一个整型值
int *(*f)(); //声明一个函数指针,返回值是一个整型指针
① int f();
在这个声明中,把f声明为了一个函数,它的返回值是一个整型值。
② int *f();
在这个声明中,要明白它的含义,要先知道这个表示式*f()是怎么求值的。()优先级高于*,所以先执行的是函数调用操作符(),因此,f是一个函数,它的返回值类型是一个指向整型的指针。
③ int (*f)();
在这个声明中,有两对括号,第2对括号是函数调用操作符,第1对括号只起到一个聚组的作用。第1对括号的出现迫使间接访问在函数调用之前进行,使f成为一个函数指针,它所指向的函数返回一个整型值。
函数指针是什么?
程序中的每个函数都位于内存中的某个位置,所以存在指向那个位置的指针,这个指针就是函数指针。
④ int *(*f)();
这个声明和第③个声明基本相同,f是一个函数指针,只是所指向的函数的返回值是一个整型指针,必须对其进行间接访问操作才能得到一个整型值。
(3)数组
int f[10]; //声明一个数组,元素类型是10个整型数据
int *f[10]; //声明一个数组,元素类型是指向整型的指针
int f()[]; //非法声明,f是一个函数,返回值是一个整型数组(后续会说明为何是非法的)
int f[](); //非法声明,f是一个数组,元素类型是返回值为整型的函数(后续会说明为何是非法的)
int (*f[])(); //声明f是一个数组,数组元素的类型是函数指针,它所指向的函数的返回值是一个整型值
① int *f[10];
在这个声明中,有两个操作符,其中下标引用操作符优先级高于间接访问操作符优先级,所以表达式*f[10]先执行下标引用,所以f是某种类型的数组(它包含的元素个数为10)。在取得一个数组元素后,随即执行的是间接访问操作。所以这个数组的元素类型是指向整型的指针。
② int f()[ ];
这个声明是非法的。f是一个函数,它的返回值是一个整型数组。但函数只能返回标量值,不能返回数组,所以这个是非法的。
③ int f[ ]();
这个声明也是非法的。f是一个数组,它的元素类型是返回值为整型的函数。但数组元素必须具有相同的长度,不同的函数显然可能具有不同的长度,所以这个也是非法的。
④ int (*f[ ])();
这个声明是合法的。这里有两对括号,他们分别具有不同的含义。括号内的表达式*f[ ]首先进行求值,所以f是一个元素为某种类型的指针的数组。表达式末尾的()是函数调用操作符,所以f肯定是一个数组,数组元素的类型是函数指针,它所指向的函数的返回值是一个整型值。
(4)函数+数组
int *(*f[])(); //声明一个指针数组,指针所指向的类型是返回值为整型指针的函数
这个声明,与前面的区别就是多了一个间接访问操作符,该操作符使指向的这个函数的返回值是整型指针。
(5)完整的函数原型
int (*f)(int,float); //声明一个函数指针,它所指向的函数接受两个参数,一个整型值,一个浮点型值,并返回一个整型值
int *(*g[])(int,float); //声明一个指针数组,数组元素是一个函数指针,它所指向的函数接受两个参数,一个整型值,一个浮点型值,并返回一个整型指针
此文章参考书籍:《C和指针》、《C Primer Plus》