首先要说明的是,在C语言中,()、[]运算符的优先级别要高于*指针运算符。
因此,下面基于运算符优先级来讨论一下C语言中指针用法里很容易混淆的几种情况:
int *p;//p为指向整型数据的指针变量
int *p[4];//p为一个指针数组,里面有4个元素,每个元素都是一个指向整型变量的指针。因为[]运算符的优先级别高,因此p首先与[4]结合,也就是说p是一个数组名,接下来再看该数组中的元素究竟是什么,从前面的int *可以看出数组中的元素是指向整型变量的指针。
int (*p)[4];//p是一个指针,它指向的是一个含有4个整型元素的数组。因为()运算符优先级别高,因此p先与*结合,这样就确定了p肯定是一个指针,接下来的工作就是看看究竟p这个指针指向什么,抛开(*p)不看,假如是int a[4]的话,那大家都会知道这个数组a是一个包含4个整型变量元素的一维数组,因此指针p就是指向这样一个数组——包含4个整型元素的数组。
int *p();//p是一个函数名称,该函数没有任何参数,该函数返回一个指针,该指针指向一个整型变量。同样,先从优先级来分析,因为()的优先级别高,因此p首先与()结合成p(),因此p就是一个函数名字,接下来再看该函数的一些特性,比如参数以及返回值之类的东西。
int (*p)();//p是一个指针,该指针指向一个函数,该函数没有参数,且返回一个整型变量。利用优先级来分析,p先与*结合,因此就能够首先确定出p是一个指针了,下面再看该指针指向什么东西,就像分析int (*p)[4]一样,抛开(*p)不看,如果是int fun()的话,就能够知道这是一个不带参数且返回整型变量的函数,因此指针p就是指向这样一个函数。
好了,有了上面的分析,相信大家对指针里这几个比较容易混淆的用法必然很清楚了,当然在指针的使用中还有指向指针的指针,比如int **p;以及指向多维数组的多重指针,但是相信有了以上基础之后,只要认真分析,肯定就能把问题迎刃而解了吧?
下面就来看一个稍微复杂些的指针方面的应用:
int (*p(char op))(int, int);
不知道大家是否可以看懂上面这一行中定义的东西,你能告诉我p是什么吗?呵呵,我先把谜底给大家,让大家一睹为快,p是一个函数名字。下面就来分析一下:
根据优先级来看p会首先与(char op)结合,因此p必定是一个函数名字,由p来表征的这个函数只含有一个字符型的参数op,并且该函数返回一个指针,如果是
int *p(char op)的话,大家都会很清楚的知道该函数会返回一个指针,且该指针会指向一个整型变量,但是对于int (*p(char op))(int, int);而言,p表征的这个函数肯定会返回一个指针,那么该指针到底会指向什么东西呢?呵呵,如果给你int (指针哈哈)(int,int),你肯定也会知道“指针哈哈”是指向一个函数的,该函数还有两个整型参数,且返回一个整型值,那么好了,知道了这一点就应该能够知道这里的p表示的真正含义了吧:p为一个函数名字,该函数带有一个char型参数,且返回一个指向函数的指针,该指针指向的函数包含两个整型参数、返回一个整型变量。哈哈,看懂没?
通常情况下,如果遇到类似问题时,我们不会把问题一次性搞得如此复杂,而是会拆解开来,一般都是先用typedef定义一个指向函数的指针,再用它定义好的这个东东去再定义一个函数,这个函数的返回值就是我们用typedef定义的那个东东哟,呵呵,请看下面的示例:
// 定义指向这类函数的指针
typedef int (*FP_CALC)(int, int);
FP_CALC s_calc_func(char op);//声明一个函数
其实,上面的两行就相当于下面的这一行啊:
int (*s_calc_func(char op))(int, int);//完成同样的功能——声明一个函数
但是如果我们不是来声明一个函数,而是来定义一个指向函数的指针变量时,
如果不用typedef的方式,那么将会是如下的样子:
int (*s_fp)(int, int);
这多少让大家不太容易接受,因为我们熟知并常见的定义变量的方式是:类型 变量名,如int a;
而上面这种方式定义变量,看似有点像函数声明了,呵呵,因此在使用到指向函数的指针时,通常都先采用typedef的方法来声明一个指向函数的指针,然后就可以用“类型 变量名”这种方式来定义了:
typedef int (*FP_CALC)(int, int);
FP_CALC s_fp;//这多好看呀,看得舒服吧?
下面再给出一个完整的引用,有兴趣的读者可以仔细研究研究,真的很有趣味:
-----------------------------------------------------------------------------------
typedef的使用中,最麻烦的是指向函数的指针,如果没有下面的函数,你知道下面这个表达式的定义以及如何使用它吗?
int (*s_calc_func(char op))(int, int);
如果不知道,请看下面的程序,里面有比较详细的说明
// 定义四个函数
int add(int, int);
int sub(int, int);
int mul(int, int);
int div(int, int);
// 定义指向这类函数的指针
typedef int (*FP_CALC)(int, int);
// 我先不介绍,大家能看懂下一行的内容吗?
int (*s_calc_func(char op))(int, int);
// 下一行的内容与上一行完全相同,
// 定义一个函数calc_func,它根据操作字符 op 返回指向相应的计算函数的指针
FP_CALC calc_func(char op);
// 根据 op 返回相应的计算结果值
int calc(int a, int b, char op);
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return b? a/b : -1;
}
// 这个函数的用途与下一个函数作业和调用方式的完全相同,
// 参数为op,而不是最后的两个整形
int (*s_calc_func(char op)) (int, int)
{
return calc_func(op);
}
FP_CALC calc_func(char op)
{
switch (op)
{
case '+': return add;
case '-': return sub;
case '*': return mul;
case '/': return div;
default:
return NULL;
}
return NULL;
}
int calc(int a, int b, char op)
{
FP_CALC fp = calc_func(op); // 下面是类似的直接定义指向函数指针变量
// 下面这行是不用typedef,来实现指向函数的指针的例子,麻烦!
int (*s_fp)(int, int) = s_calc_func(op);
// ASSERT(fp == s_fp); // 可以断言这俩是相等的
if (fp) return fp(a, b);
else return -1;
}
void test_fun()
{
int a = 100, b = 20;
printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));
printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));
printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));
printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));
}
运行结果
calc(100, 20, +) = 120
calc(100, 20, -) = 80
calc(100, 20, *) = 2000
calc(100, 20, /) = 5