一些复杂的声明
- 声明时可使用的符号:
* --- 表示一个指针 ()--- 表示一个个函数 []--- 表示一个数组
- 示列:
```
int board[8][8]; //声明一个内含数组的数组
int ** ptr; //声明一个指向指针的指针,被指向的指针指向int
int * risks[10]; //声明一个内含10个元素的数组,每个元素都是一个指向int的指针
int (* rusks)[10]; //声明一个指向数组的指针,该数组内含10个int类型的值
int (* uuf)[3][4]; //声明一个3 X 4的二维数组,每个元素都是指向int的指针
int (* uuf)[3][4]; //声明一个指向3 X 4二维数组的指针,该数组中内含int类型的值
int (* uuf[3])[4]; //声明一个内含3个指针元素的数组,其中每个指针都指向一个内含4个int类型元素的数组。
```
- `*`、`()`、`[]`的优先级及结合规则:
1. 数组名后面的`[]`和函数名后面的`()`具有相同的优先级。比`*`的优先级高。
2. 从左往右结合。
- 根据这些规则可进行如下形式的声明:
char * fump(int); //返回字符指针的函数
char (* frump)(int); //指向函数的指针,该函数的返回类型为char
char (* flump[3])(int); //内含3个指针的数组,每个指针都指向返回值为char的函数
函数和指针
#### 什么是函数指针
- 函数也有地址,因为函数的机器语言实现由载入内存的代码组成。
- 指向函数的指针中储存着**函数代码的起始处的地址**。
#### 声明函数指针
> 声明数据指针时,必须声明指针所指向的数据类型。
> 同样,声明函数指针时,**必须声明函数指针指向的函数类型**;为了指明函数类型,要指明函数签名(即,函数的返回类型和参数类型)。
eg:有下面函数原型:
void ToUpper(char *); //把字符串中的字符转换成大写字符
ToUpper()函数的类型是带`char *`类型参数,返回类型是`void`的函数。
声明一个指针pf指向该函数类别:
void (pf)(char); //pf是一个指向函数的指针;把函数名ToUpper替换成表达式(*pf)
声明一个指向某类型函数的指针 最简单的方式:
1. 写出该函数的原型
2. 把函数名替换成(`*pf`)形式的表达式。即可创建函数指针声明(pf为指向该类型函数的指针)。
使用typedef:
typedef void (*V_FP_CHARP)(char *);
void show (V_FP_CHARP fp, char *);
V_FP_CHARP pfun
note:
void *pf(char *); //pf不是函数指针,是一个返回字符指针的函数
声明了函数指针以后,可以把类型匹配的*函数地址*赋给函数指针。这种上下文中,函数名可用于表示函数地址。eg:
void ToUpper(char *);
void ToLower(char *);
int round(double);
void (*pf)(char *);
pf = ToUpper; //有效
pf = ToLower; //有效
pf = round; //无效,round与指针类型不匹配
pf = ToLower(); //无效,ToLower()不是地址,且ToLower()的返回值是void,没有返回值,不能在赋值语句中进行赋值。
#### 使用函数指针
> 可以使用数据指针访问数据,同样也可以使用**函数指针访问函数**
- 存在两种语法:两种用法都可以
eg:
```
void ToUpper(char *);
void ToLower(char *);
void (*pf)(char *);
char mis[] = "Nina Metier";
pf = ToUpper;
(*pf)(miss) //把ToUpper作用于语法1
pf = ToLower;
pf(miss); //把ToLower作用于语法2
```
- 语法1:由于pf指向ToUpper函数,`*pf`相当于ToUpper函数,所以`(*pf)(miss)`和`ToUpper(miss)`相同;从声明可看出ToUpper和`*pf`是等价的。
- 语法2:由于函数名是指针,所以指针和函数名可以互换使用,所以`pf(miss)`和`ToLower(miss)`相同;从pf的赋值表达式语句可看出ToLower和pf是等价的
- 历史原因:贝尔实验室的C和UNIX采用的是语法1,伯克利的UNIX采用的是语法2;为保证兼容,ANSI C认为`(*pf)(miss)`与`pf(miss)`等价。
- 函数指针的常见用法:
1. 作为函数的参数:
```
void show(void (* fp)(char *), char * str); //声明了两个形参,fp--函数指针(fp指向的函数接受char *类型的参数,返回值为void),str--数据指针(str指向一个char类型的数值)
//调用函数:
show(ToLower, miss); //show()使用ToLower()函数:fp = ToLower
show(pf, miss); //show()使用pf指向的函数: fp = pf
//show()函数定义
void show(void (* fp)(char *), char * str)
{
(*fp)(str); //把所选函数作用于str,用fp指向的函数转换str
puts(str); //显示结果
}
```
note:带返回值的函数作为参数传递给另一个函数有两种方式:
function1(sqrt); //传递sqrt函数的地址; 假设function1()代码中会使用该函数
function2(sqrt(4.0)); //传递sqrt函数的返回值; 先调用sqrt()求值,把返回值传递给function2()
#### 使用函数名的4种方法:定义函数、声明函数、调用函数、作为指针
int comp(int x, int y); //函数原型中的函数名
status = comp(q, r); //函数调用中的函数名
int comp(int x, int y) //函数定义中的函数名
{
…
}
pfunct = comp; //在赋值表达式语句中,作为指针的函数名
slowsort(arr, n, comp); //作为指针参数的函数名
> 参考资料:C primer Plus