C语言面试题详解(第9节)
发表于: 2019-02-25 22:15:40 | 已被阅读: 77 | 分类于: C语言
基本上,每个C语言工作者都认可指针非常重要。事实也的确如此,正是因为指针的存在,C语言才能如此灵活,才能在计算机编程语言几十年的发展中,始终占有一席之地。
C语言的设计宗旨是:

而有些C语言初学者却认为指针是不可捉摸的,甚至有些仇视指针,觉得指针是一种古老的、不安全的设计,应该被摒弃。更有甚者,直接就放弃学习C语言了。但是,世界上那么多C语言程序员,他们都是聪明绝顶的吗?显然不是,他们都是和我们一样的普通人,只不过“闻道有先后”而已。其实

先来看这个题目热热身
这个题目是我国台湾省某著名杀毒软件公司的一道面试题,请看C语言代码如下:
#include <stdio.h>
int main()
{
int max(x, y);
int *p = &max;
int a, b, c, d;
printf("Please input three integer\n");
scanf("%d%d%d", a, b, c);
d = (*p)((*p)(a, b), c);
printf("Among %d, %d, and %d, the max integer is %d\n",
a, b, c, d);
return 0;
}
int max(int x, int y)
{
return x>y?x:y;
}

上面这段C语言程序是有问题的,那么哪几行有问题呢?以及为什么呢?
分析
显然,这道题考的是C语言的语法,那么编译器就能协助我们定位错误,输入编译命令:
# gcc t1.c
得到如下提示信息,应该注意每一个警告和错误:

...
int main()
{
int max(int, int);
...
scanf("%d%d%d", &a, &b, &c);
...
再次编译,得到如下提示信息:

int *p = &max;
// 修改为
int (*p)(int, int) = &max;
修改很简单,无非就是将 p 改为
# gcc t1.c
# ./a.out
Please input three integer
1 2 3
Among 1, 2, and 3, the max integer is 3
不要把指针“特殊化”
初学者看到“函数指针”这样的字眼,可能又有些烦了:以前知道有 int 指针,float 指针,后来知道还有数组指针,指针数组,指针函数,现在又来一个函数指针,指针到底有几种?这样想其实就把指针“特殊化”了,反而不利于理解指针。其实,只要把指针像 int、float 一样看作是C语言中的一种数据类型,似乎一切就很简单了。

作为练习,再来看看下面这个面试题
这是美国某著名计算机嵌入式公司的一道面试题,请看C语言代码如下:
float(**def)[10];
double*(*gh)[10];
double(*f[10])();
int*((*b)[10]);
long (*fun)(int);
int (*(*f)(int, int))(int);

问:上面这段C语言声明语句代表了什么?
首先来看第 5 个,我们上面才说过,显然 fun 是一个函数指针,它指向只有一个 int 型参数,返回值为 long 的函数。
类似的,第 3 个也就好理解了,[] 优先级比 * 优先级高,因此 f 首先是一个有 10 个元素的数组。数组里存放什么类型的元素呢?我们先把 f[10] 遮住,只看 double ( * )(); ,显然,它是函数指针类型。总体来看:
double (*f[10])();
f 是一个数组,它有 10 个元素,每个元素都是一个函数指针,指向没有参数,返回值为 double 的函数
再来看第 6 个,先只看 (* f)(int, int),显然这是一个指向两个int参数的函数指针,那么它的返回值是什么呢?同样的,先遮住 (* f)(int, int),得到 int(* )(int),很明显,这也是一个函数指针,它指向有一个int型参数,返回值为 int 的函数。结合起来看:
int (*(*f)(int, int))(int);
f 是一个函数指针,它指向的函数有两个 int 型的参数,返回值也是一个函数指针(指向有一个int型参数,返回值为 int 的函数)。

现在再来看第 2 个就简单了,它也是一个数组指针,也指向有 10 个元素的数组,只不过该数组里存放的都是 double * (double 型指针)。第 4 个就更简单了,它就相当于 int* (* b)[10],和第 2 个是非常类似的。
小结
你看,只要不对指针搞“特殊化”,像 int 、float 一样,把它当作是一种数据类型,一切就简单了。应明白,C语言只是一门基础工具,它并不是智商拔尖的精英专用工具,别人都能学好它,聪明的我们也一定能!