相当一部分程序员在求职时都非常厌烦,也非常鄙视公司拿出一套“偏题”“怪题”,要求求职者做出答案。似乎这是一种“侮辱”,所以有些程序员甚至直接就炒掉这家公司,甩袖子走人了。
我曾经也非常反感这样的招聘方式:我的能力可不在于纠结这些“'茴'字有几种写法”的无聊问题,程序员的精力应该放在项目架构设计上,尽快把业务做完吧。何况,相当多的笔试题、面试题一点实际意义也没有,在项目中写出那些“偏题”“怪题”中风格的代码的程序员一定都是脑子秀逗了...
为什么要琢磨那些奇怪的C语言面试题?
然而,即使是谷歌、IBM这样注重实践的世界一流高科技公司,也是会通过一些看起来非常奇怪的笔试题筛选求职者的。其实仔细想想,笔试题即使再怪,也不会是计算火星绕太阳的轨道参数的,从某些角度来看,所谓的怪题,只不过是非常注重基础而已。
可能一些问题小红觉得非常“怪”,但是在小明看来却简单到“弱智”,这就说明小红的基础没有小明扎实。
尤其是嵌入式C语言开发,基础非常重要,不注重基础的程序员写出的代码常会有一些隐患,而且可能某天程序崩溃了,他也无法定位出错误,因为他根本不知道为什么出错,甚至会对问题代码视而不见。
诚然,一些笔试题看起来的确非常弱智,甚至会让指针指向一个非法地址,或者直接让 0 做除数了,例如下面这两句C语言代码:
void* p = (void*)1;
int res = val/0;
显示的问题当然好避免,但是预防一些类似的隐式问题就依赖程序员扎实的基础了,例如下面这几句C语言代码:
int a = 8, b = 10;
int c = a/b;
float d = 19.2/c;
上面这段C语言代码的问题和 int res = val/0; 是类似的,只不过隐藏的稍深一些,但是某个不注重基础的程序员可能根本就看不出这段C语言代码有问题。如果问题隐藏的再深一点呢?
事实上,那些看起来非常弱智的题目可能来自招聘公司的某个项目开发。有可能有次公司的某个项目出了一次大问题,花了很多人力物力才定位解决问题。
在一次笔试中,招聘公司不可能直接把复杂的项目搬给求职者,但是又非常希望考查求职者是否懂得该问题,于是退而求其次,把问题简化,变成了一个小红觉得很“怪”,小明觉得很“弱智”的题目。
本系列文章琢磨一些知名公司的面试、笔试题只是手段,我们并不是为了做题而做题,而是为了查漏补缺,巩固自身的基础。基础扎实的程序员,才能不惧任何挑战。
来看看这个问题
下面这个问题来自美国著名硬盘S公司的面试题,请看C语言代码如下,它会输出什么呢?
#include <stdio.h>
int main()
{
int a[10], i;
int *p, *q;
for(i=0;i<10;i++)
a[i] = i;
p = a;
q= &a[2];
printf("%d\n", a[q-p]);
return 0;
}
上面这个C语言程序非常简单,S公司其实就是想考察求职者是否懂得指针之间的减法运算而已。p 和 q 是 int 指针,p 指向 a,q 指向 a[2],那么 q-p 等于多少呢?
分析
在我的 x86_64 机器上,int 型占用 4 字节内存空间,也即数组 a 每个元素都占有 4 字节内存空间。若 a 的地址为 addr,那么显然 a[1] 的地址为 addr+4,a[2] 的地址为 addr+8。这么看来,q-p 就等于 8,上面这个C语言程序会输出 8 了?
得到答案最好的办法就是编译该 C语言程序并运行之:
# gcc t.c
# ./a.out
2
奇怪,C语言程序居然输出的值居然是 2,怎么回事?难道我们分析数组 a 的地址分析错了?在程序中添加下面这句C语言代码:
printf("p:%p, q:%p\n", p, q);
再次编译运行,得到如下答案:
# gcc t.c
# ./a.out
p:0x7fffaef7ad90, q:0x7fffaef7ad98
2
p 和 q 的值的确相差 8!看来我们分析数组 a 的地址没有错。为什么这个C语言程序会输出 2 呢?
读者应该注意,p 和 q 都是 int 型指针,所以通过 p 和 q 访问内存时都是逐 sizeof(int) 字节(这里等于 4 字节) 进行的,也就是说,内存地址相差 8 对于 p 和 q 而言,也仅仅只够存放 2 个元素。因此计算 q-p 时,编译器会考虑它们的数据类型,实际上 q-p 等于 (0x7fffaef7ad98-0x7fffaef7ad90)/sizeof(int) 也即是 2。
关于指针类型与访问内存方式的关系,我的这篇文章说的比较清楚,读者感兴趣的话可以看看:指针为何要有类型。
小结
你看,如果脑海里没有指针减法的概念,这样的问题就很有可能处理错。在项目开发中,万一把 q-p 当作 8 了,不就埋下了一个较难发现的隐患了吗?