C/C++程序员工作面试的秘密

稍微懂些硬件知识是非常危险的。一位程序员把一张新奇的能演奏颂歌的圣诞卡片拆了开来,取出其中的压电乐曲芯片。他偷偷地把它安装在老板的键盘上,并连接到一个发光二极管上。他进行了测试,一个能够点亮发光二极管的电压足以驱动其中一块芯片。

接着,我(噢!说错了,我指的是那位程序员)修改了系统编辑器,当它启动时点亮发光二极管,当它退出时关闭发光二极管。结果:只要老板一使用这个编辑器,他的终端就会持续演奏圣诞颂歌!半小时以后,隔壁办公室的人们群情激愤,蜂拥而至,迫使老板停下工作,直到肇事原因被发现为止。

—— The Second Official Handbook of Practical Jokes[1]

A.1 硅谷程序员面试

本附录提供了一些在顶级公司寻找位置的C程序员面试过程的提示。尖端计算机产业最值得称道的事情之一就是选择新雇员加入队伍的不寻常方法。在许多产业中,管理者或经理全权负责员工的录取,但事实上他所提出的应征条件往往只有他自己才符合。但是,在软件开发的尖端领域,尤其是高科技企业刚刚启动时,程序员往往比决定哪位候选人是技术最佳的“个人应征者”的经理更有资格说三道四。需要做一些系统开发的天才程序员极为罕见,对他的要求也格外具体。所以有时候技术能力是你寻求工作面试时惟一重要的特长。

所以,程序员面试就形成了一种非常独特的风格。经理根据公司的策略,在众多面试者中寻找人才。那些有望入围者接着要进行一番技术上的严格考核,考核者是开发队伍的每个人,而不仅仅是经理。一个典型的工作面试将持续一整天,包括连续与六七个不同的工程师进行一小时左右的会谈——他必须让所有人信服他的确有能力加入到开发小组中,才能得到一份工作承诺。

工程师们常常有一些自己最喜欢问的问题,本章就包含了一些工程师们喜欢的问题。泄露这些“机密”并无害处——一位阅读了本书的程序员很可能已经拥有足够的知识,足以加入一家优秀的软件公司。这些问题中的许多源于我们尝试编程的真实算法,现在已经被其他人用新的问题所取代。当然,你在面试候选人时并不仅仅看重他们对问题作什么样的反应,你常常也很在意他们是怎样做出反应的。他们是不是对一个问题深思熟虑,提出几种可能性,还是在脑子里一有想法就脱口而出?他们在说明自己的思路时所提的论据是否有足够的说服力?他们是不是对一个明显错误的策略固执己见,还是思维灵活,很快就完善自己的答案?下面的有些问题产生了最奇怪的答案。你可以自己试验一下,掂量一下自己的份量!

A.2 怎样才能检测到链表中存在循环

这个问题看上去比较简单,“怎样才能检测到链表中存在循环?”但提问者不断对问题施加一些额外的限制,使这个问题很快就变得面目狰狞。

通常第一种答案:

对访问过的每个元素作个标记,继续遍历这个链表,如果遇到某个已经做过标记的元素,说明链表存在循环。

第二个限制:

这个链表位于只读内存区域,无法在元素上作标记。

通常第二种答案:

当访问每个元素时,把它存储在一个数组中。检查每一个后继的元素,看看它是否已经存在于数组中。有时候,一些可怜的程序员会纠缠于如何用散列表来优化数组访问的细节之中,结果在这一关卡了壳。

第三个限制:

噢!内存空间非常有限,无法创建一个足够长度的数组。然而,可以假定如果链表中存在循环,它出现在前N个元素之中。

通常第三种答案(如果这位程序员能够到达这一步):

设置一个指针,指向链表的头部。在接下去对直到第N个元素的访问中,把N-1个元素依次同指针指向的元素进行比较。然后指针移向第二个元素,把它与后面N-2个元素进行比较。根据这个方法依次进行比较,如果出现比较相等的情况就说明前N个元素中存在循环,否则如果所有N个元素两两之间进行比较都不相等,说明链表中不存在循环。

第四个限制:

噢!不!链表的长度是任意的,而且循环可能出现在任何位置。(即使是优秀的候选者也会在这一关碰壁)

最后的答案:

首先,排除一种特殊的情况,就是3个元素的链表中第2个元素的后面是第1个元素。设置两个指针p1和p2,p1指向第一个元素,p2指向第三个元素,看看它们是否相等。如果相等就属于上述这种特殊情况。如果不等,把p1向后移一个元素,p2向后移两个元素。检查两个指针的值,如果相等,说明链表中存在循环。如果不相等,继续按照前述方法进行。如果出现两个指针都是NULL的情况,说明链表中不存在循环。如果链表中存在循环,用这种方法肯定能够检测出来,因为其中一个指针肯定能够追上另一个(两个指针具有相同的值),尽管有可能要对这个链表经过几次遍历才能检测出来。

这个问题还有其它一些答案,但上面所说的几个是最常见的。

编程挑战

寻找循环

证明上面最后一种方法可以检测到链表中可能存在的任何循环。在链表中设置一个循环,演练一下你的代码;把循环变得长一些,继续演练你的代码。重复进行,直到初始条件不满足为止。同样,确定当链表中不存在循环时算法可以终止。

提示:编写一个程序,然后依次往外推演。

A.3 C语言中不同的增值语句的区别何在

考虑下面四条语句:

  x = x + 1;      /* 正规形式 */
  ++x;           /* 前缀自增 */
  x++;           /* 后缀自增 */
  x += 1;         /* 复合赋值 */

显然,这四条语句的功能是相等的,它们都是把x的值增加1。如果像现在这样不考虑前后的上下文环境,它们之间并没有什么区别。应试者需要(隐式或显式地)提供适当的上下文环境,以便回答这个问题并找出这四条语句之间的区别。注意最后一条语句是一种在算法语言中表达“x等于x加上1”的便捷方法。因此,这条语句仅供参考,我们需要寻找的是其余三条语句的独特性质。

绝大多数C程序员可以立即指出++x是一种前缀自增,当它先增加x的值然后再在周围的表达式中使用x的值。而x++是一种后缀自增,它先在周围的表达式中使用x的值然后再增加x的值。有些人认为C语言存在“++”和“--”操作符的惟一原因是*p++在PDP-11(第一个C编译器所用的机器)机器上可以用一条单一的机器指令来表示。事实并非如此,这个特性继承了PDP-7上的B语言,但自增和自减操作符在所有的硬件系统中的应用之广令人难以置信。

有些程序员则在此处未作深入考虑,忽视了当x不是一个简单的变量而是一个涉及数组的表达式时,像x += 1这样的形式是很有用的。如果你有一个复杂的数组引用,并需要证明同一种下标形式在两种引用中都可以使用,那么

node[i>>3] += -(0x01 << ( i & 0x7));

就是你应该采用的方法。这个例子是我直接从操作系统的代码中取出来的,只有数据名作了改动(为了保密起见)。优秀的应试者还能够指出左值(定位一个对象的表达式的编译器用语——通常具有一个地址,但它也可能是一个寄存器,也可能是地址或寄存器加上一个位段)只被计算了一次。这一点非常重要,因为下面的语句:

mango[i++] += y;

被当作

mango[i] = mango[i] + y; i++;

而不是

mango[i++] = mango[i++] + y;

以前,当我们对一些申请Sun的Pascal编译器队伍的位置的候选人进行面试时,最好的那位候选人(他最终获得了这个工作——嗨!Arindam)解释说这些区别与编译器的中间代码有关,例如“++x”表示取x的地址,增加它的内容,然后把值放在寄存器中;“x++”则表示取x的地址,把它的值装入寄存器中,然后增加内存中的x的值。顺便问一句,使用编译器的术语,另外两条语句应该怎么描述?

尽管Kernighan和Ritchie认为自增操作比直接加1更有效率(K&R2, 第18页),但目前所使用的当代编译器通常在这方面都做得很好,使这几种方法的速度都一样。如果没有任何能够显示它们之间区别的相关上下文环境,现代的C编译器在编译这些语句时应该产生相同的指令。它们应该是增加一个变量时最快的一种指令。你可以在喜欢的编译器上编译这些代码,编译器应该有一个选项,可以产生一个汇编指令列表。你也可以把编译器设置为调试模式,这样也常常可以使检查对应的C语句和汇编指令更为容易。不要使用优化选项,因为这些语句有可能因为优化而被精简掉。在Sun的工作站中,附上神奇的魔咒“-S”,使命令行看上去如下:

cc –S –Xc banana.c

这个-S选项使编译停在汇编阶段,把汇编语言指令输出到banana.s文件中。最新的编译器SPARCompilers 3.0作了改进,当使用这个选项时,它可以使源代码散布于汇编程序输出文件中。这就使得寻找问题和诊断代码生成变得更加容易。

-Xc选项告诉编译器拒绝任何不符合ANSI C的代码结构。当编写新代码时始终使用这个选项是一个好主意,因为它有助于程序获得最大程度的可移植性。

所以,有时候区别就在于哪一个在源代码中看上去更好一点。一般较短的形式比较长的形式更容易阅读一些。然而,过度简洁也会导致代码难以阅读(你只要问问那些试图修改其它人的APL代码的人就知道了)。当我还是一个系统编程研究生班级的助教时,一位学生让我看一些代码,他说代码里存在一个未知的Bug,但是由于代码过于紧凑,所以无法把它找出来。在一些高年级C程序员的嘲笑声中,我们系统地把类似下面的单行代码:

frotz[--j + i++] += --y;

扩展为功能相同但长度更长的:

--y;
--j;
frotz[j+i] = frotz[j+i] + y;
i++;

这让那位喜爱玩弄技巧的程序员颇感懊恼,使用这种方法,我们一下子就发现其中一个操作位置有误。

教训:不要在一行代码里实现太多的功能

这种做法并不能使编译器产生的代码更有效率,而且会使你丧失调试代码的机会。正如Kernighan和Plauger所指出的那样,“人人都知道调试比第一次编写代码要难上一倍。所以如果在编写代码时把自己的聪明发挥到极致,那么在调试时又该怎么办呢?”[2]

A.4 库函数调用和系统调用区别何在

有一个问题我们时常用来考察候选人是否知道他编程的方法是否简单,“库函数调用和系统调用的区别何在?”令人惊奇的是,许多人从来没有想过这个问题。我们并不曾见到许多描述这个区别的书籍,所以这是个很好的问题,可以判断候选人是否具有丰富的编程经验以及是否具有找出这类问题的答案的敏锐感觉。

简明的回答是函数库调用是语言或应用程序的一部分,而系统调用是操作系统的一部分。你要确保弄懂“trap(自陷)”这个关键字的含义。系统调用是在操作系统内核发现一个“trap”或中断后进行的。这个问题的完整答案需要覆盖表A-1中列出的所有要点。

表A-1 函数库调用vs.系统调用

C/C++程序员工作面试的秘密

库函数调用通常比行内展开的代码慢,因为它需要付出函数调用的开销。但系统调用比库函数调用还要慢很多,因为它需要把上下文环境切换到内核模式。在SPARC工作站上,我们对一个库函数调用进行记时(就是一个过程调用的速度),结果大约是半微秒。系统调用所需要的时间大约是库函数调用的70倍(35微秒)。纯粹从性能上考虑,你应该尽可能地减少系统调用的数量。但是,你必须记住,许多C函数库中的程序通过系统调用来实现功能。最后,那些相信麦田里的怪圈的人们会对system()函数实际上是一个库函数这个概念感到困惑。

A.5 文件描述符与文件指针有何不同

这个问题是前面一个问题的自然延续。所有操纵文件的UNIX程序或者使用文件指针,或者使用文件描述符来标识它们正在操作的文件。它们是什么?什么时候应该使用?事实上答案非常直截了当,它取决于你对UNIX I/O的熟悉程度以及对各种因素利弊的权衡。

所有操纵文件的系统调用都接受一个文件描述符作为参数,或者把它作为返回值返回。“文件描述符”这个名字多少显得有点命名不当。在Sun的编译器中,文件描述符是一个小整数(通常在0-255之间),用于索引开放文件的每个进程表(per-process table-of-open-files)。系统I/O调用有creat(), open(), read(), write(), close(), ioctl()等,但它们不是ANSI C的一部分,不会存在于非UNIX环境。如果你使用了它们,你的程序将失去可移植性。因此,建立一组标准I/O库调用是必要的,ANSI C现在规定所有的编译环境都必须支持它们。

为了确保程序的可移植性,应该使用标准I/O库调用,如fopen(), fclose(), putc(), fssek()等——它们中的绝大多数名字中带有一个“f”。这些调用都接受一个类型为指向FILE结构的指针(有时称为流指针)的参数。FILE指针指向一个流结构,它在中定义。结构的内容根据不同的编译器有所不同,在UNIX中通常是开放文件的每个进程表的一个条目。在典型情况下,它包含了流缓冲区、所有用于提示缓冲区中有多少字节是实际的文件数据的变量以及提示流状态的标志(如ERROR和EOF)等。

C库函数fdopen()可以用于创建一个新的FILE结构,并把它与一个确定的文件描述符相关联(可以有效地在文件描述符小整数和对应的流指针间进行转换,虽然它并不在开放文件表中产生一个额外的新条目)。

A.6 编写一些代码,确定一个变量是有符号数还是无符号数

有一位同事在接受Microsoft面试时,其中一个题目就是“编写一些代码,确定一个变量是有符号数还是无符号数”。这实际上是一个相当难的问题,因为它留下了太多的空间让你去理解这个问题。有些人错误地把“有符号数”同“具有负号”等同起来,以为这个问题只需要一个小小的函数或宏,测试变量的值是否小于零就可以了。

问题自然没有这么简单。要回答这个问题,你必须在特定的编译器中确定一个给定的类型是有符号数还是无符号数。在ANSI C中,“char”既可以是有符号数,也可以是无符号数,这是由编译器决定的。当你编写的代码需要移植到多个平台时,知道类型是不是有符号数就非常有用了,如果该类型在所有的编译器编译时都是恒定的,那就再理想不过了。

你无法用函数实现目的。函数形式参数的类型是在函数内部定义的,所以它无法穿越调用这一关。因此,你必须编写一个宏,根据参数的声明对它进行处理。

接下来就是区别宏的参数到底是一个类型还是一个类型的值。假定参数是一个值,无符号数的本质特征是它永远不会是负的,有符号数的本质特征是对最左边一个位取补将会改变它的符号(比如2的补码表示,它肯定是个负数)。由于作为参数的这个值的其它位与这个测试无关,你可以对它们全部取补,结果是一样的。因此,可以像下面这样尝试:

#define ISUNSIGNED(a)  (a >=0 && ~a >= 0)

如果宏的参数是一个类型,其中一个方法是使用类型转换:

#define ISUNSIGNED(type) ((type)0 – 1 > 0)

面试的关键就在于正确理解问题!你需要仔细地听,如果不理解问题或者觉得它的定义不清,可以要求一个更好的解释。第一个代码例子只适用于K&R C,新的类型提升规则导致它无法适用于ANSI C。练习:解释一下为什么,并提供一个适用于ANSI C的解决方案。

Microsoft的绝大部分问题都想考察你在压力下能够怎样思考问题,但它们并不都是技术性的。一个典型的非技术性问题可能是“美国一共有多少个加油站?”或“美国一共有多少个理发店?”他们想看看你是否作出正确的猜测和估计,或者能够提供一种寻找更可靠答案的好方法。建议:打电话给各个州的执照发放机构,只要50个电话,你就可以获得准确的数字。或者,你也可以选六七个有代表性的州,根据样本推断出总体数量。你甚至可以像一位环保主义者那样回答,当被问及“美国有多少个加油站时”时,她生气地回答:“太多了!”

A.7 打印一棵二叉树的值的时间复杂度是多少

这个问题是面试者在申请Intel编译器小组的一个职位时被问到的。现在,关于复杂度理论首先需要知道的是大O表示法。O(N)表示当N(通常是需要处理的对象数量)增长时,处理时间几乎是按照线性增长的。类似,O(N2)表示当N增长时,处理时间的增长要快得多,大致是按照N的平方增长的。关于复杂度理论你其次需要知道的是在一棵二叉树中,所有的操作的时间复杂度都是O(log(n))。所以,很多程序员不假思索地作出了这个回答。错误!

这个问题有点类似于Dan Rather著名的“频率是什么?Kenneth”问题——这个问题用于干扰、混淆和激怒对方而不是真的向对方咨询信息。要打印一棵二叉树所有结点的值,你必须对它们逐个访问,所以时间复杂度为O(N)。

我的一些同事在接受惠普公司电子工程师职位的面试时,也遇到了类似的陷阱问题。这个问题是:在一个理想的没有阻抗的电路中,一个充了电的电容器和一个未充电的电容器突然接触在一起时,会发生什么情况?机械工程师职位的面试题则是两根质量忽略不计的弹簧从平衡位置拉紧,然后松开会发生什么?主考官分别运用两个不同的物理定理 (如电容器例子中电荷守恒定理和能量守恒定理) 推导出两个不同的结论,然后他询问面试者为什么会出现两种不同的结果?原因何在?

这里的陷阱在于主考官至少在表达其中一个结论时使用了一个割裂了初始条件和结束条件的积分公式。在现实世界中,这确实没错,但在理论性的实验上,它导致了对不连续状态的积分(因为减速效果被理想化了)。这样,这个公式不再适用。工程师很可能以前从来没有碰到过这类问题。但是,这些类似无质量弹簧和无阻抗电路的问题每次当你遇上时都会使你难堪!

但是,应试者在申请一家大型管理咨询公司的一个软件顾问职位时,主考官又抛出了另一个弧线球,问题是“如果execve系统调用成功,它将返回什么?”回顾一下,execve()函数用参数中的可执行文件替换调用者进程的映像并开始执行。所以,当execve系统调用成功执行后,它并不会返回一个值。把这些陷阱问题用于刁难你的朋友确实很有趣,但如果在面试中遇到它们就不太有趣了。

A.8 从文件中随机提取一个字符串

这也是Microsoft喜欢使用的问题之一。主考官要求面试者编写一些代码,实现从一个文件(文件的内容是许多字符串)中随机提取一个字符串。解决这个问题经典的方法是读取文件,对字符串进行计数,并记录每个字符串的偏移位置。然后,在1和字符串总数之间取一个随机数,根据选中字符串的偏移位置取出该字符串。

但是,主考官设置了一些条件,使这个问题的难度大大增加。他要求只能按顺序遍历文件一次,并且不能使用表格来存储所有字符串的偏移位置。对于这个问题,主考官的主要兴趣在于你如何解决问题的过程。如果你提问,他会给你一些提示,所以大多数面试者最终都能获得答案。主考官对你的满意程度取决于你获得答案的速度。

基本的技巧是在幸存的字符串中挑选,并在过程中不断更新。从计算的角度看这个方法是非常低效的,所以它很容易被忽略。你打开文件并保存第一个字符串,此时就有了一个备选字符串,并有100%的可能性选中它。保存这个字符串,继续读入下一个字符串,这样就有了两个备选字符串,选中每个的可能性都是50%。选中其中之一并保存,然后丢弃另一个。再读入下一个字符串,按照新字符串33%原先幸存的字符串67%的概率(它代表前两个字符串的幸存者),在两者之间选择一个,然后保存新选中的字符串。

根据这个方法,依次对整个文件进行处理。在其中每一步,读入字符串N,在它(按照1/N的概率)和前一个幸存的字符串(按照N-1/N的概率)之间进行选择。当到达文件末尾的时候,最后一个幸存的字符串就是从整个文件中随机提取的那个字符串!

这是一个非常艰难的问题,你要么依靠尽可能少的提示获得答案,要么就预先做好充分准备,提前阅读本书。

A.9 轻松一下——如何用气压计测量建筑物的高度

我们觉得这些问题乐趣无穷,甚至还把它们应用到自己的非计算机环境中。Sun有一个叫“junk mail”的e-mail账号,让员工们共享偶然兴之所致得到的灵感。有时候,人们把问题放到这个账号中,并要求其它工程师进行比赛,提交最佳答案。这里就有这样一个难题,它是最近才放上去的。

有一个很早的故事,讲的是一位物理系学生寻找新奇的方法用气压计测量一幢建筑物的高度。Alexander Calandrain在The Teaching of Elementary Science and Mathematics[4]中引述了这个故事。

一位学生考试被判不及格,因为他拒绝使用班上老师所教的方法回答问题。当这名学生提出抗议时,学校指定我担任仲裁人。我来到教授的办公室,阅读了考试题:“怎样在气压计的帮助下测量一幢高楼的高度。”

这位学生是这样回答的:“把气压计带到楼顶,用一个长绳系住。把气压计放低,直到触及街面,然后再提起来,测量绳子的长度。绳子的长度就是建筑物的高度。”

高分的回答应该是充分运用物理学的原理,但这个回答显然没说明这一点。我提议给这位学生另一次机会回答这个问题。我给了这位学生6分钟时间,并警告他答案必须与物理学的知识有关。结果他只用了一分钟就交上了答案:“把气压计带到楼顶,倚在屋顶的边缘上,然后放开气压计,并用秒表进行计时。然后,运用物体下坠公式:S=1/2 a t2计算建筑物的高度。”此时,我毫不犹豫地给了这位学生满分。

这位学生继续说出了3种运用气压计测量建筑物高度的方法:

在阳光灿烂的日子里,测量气压计的高度、气压计影子的高度以及建筑物影子的高度,然后运用简单的比例原理,计算出建筑物的高度。

带上气压计走上建筑物的楼梯。当你爬楼梯时,用气压计的高度在墙上作标记。到达楼顶后,数一下标记的数量,你就可以得到以气压计高度为单位的建筑物高度。

最后一种方法(也许最不可行)是把气压计送给建筑物的管理员,让他告诉你建筑物的高度。

当这个老掉牙的故事作为一个“科学难题”出现在Sun时,人们又重新激起了对它的热情,总共提出了16种新的用气压计测量建筑物高度的好方法。这些方法如下:

气压法:分别测量楼顶和楼底的气压,然后根据气压差计算大楼的高度。这个方法是这个问题最初设计时的标准答案,也是测量大楼高度最不精确的方法之一。

钟摆法:来到建筑物的顶部,用绳子系住气压计,把它放低到地面。然后晃动气压计,测量钟摆的摆动时间,根据摆动时间可以计算出钟摆的长度,也就是建筑物的高度。

贪婪法:把气压计当掉,换取一点种子基金。然后用连锁信方法(或称神秘链方法)积累一大笔钱,把这笔钱堆得和大楼一样高,然后根据每张纸币的厚度和纸币的张数计算大楼的高度。这个方法并没有提及如何在警察闻讯赶来之前完成对大楼的测量。

黑手党法:用气压计作为武器,威逼大楼的管理员说出大楼的高度。

弹道法:在地面上用一架迫击炮把气压计送上半空,让它正好到达楼顶的高度。你可能需要进行几次距离修正发射以获得刚好能把气压计送到大楼高度的发射方法。运用标准弹道计算表,你可以计算出这次弹道发射的高度,也就是大楼的高度。

镇纸法:把气压计作为镇纸压在建筑物设计图纸上,然后从图纸上找出建筑物的高度。

音速法:从大楼的顶部把气压计扔下来,测量气压计撞击地面和你听到撞击声的时间差。在实际可行的距离内,视觉传递的时间可以忽略不计,而声音的传递速度(在标准温度和气压条件下是340m/s)是已知的,根据上面这些数据可以计算出大楼的高度。

反射法:把气压计的玻璃面作为镜子,测量镜面反射亮光从楼顶到地面的来回时间,由于光的速度是一个已知量,所以大楼的高度也可以据此测出。

商业法:卖掉气压计,用这笔钱买一些适当的仪器测量大楼的高度。

类比法:用一根绳子系住气压计,把绳子绕在一个小型发电机的轴上。然后把气压计从大楼顶上扔下来,绳子就会使发电机转动。测量气压计从楼顶掉到地面期间发电机所发的电。发电机产生的电能和轴旋转的圈数是成正比的,根据这些数据可以算出楼顶到地面的高度。

三角法:在地面上选一点,它和大楼的距离是已知的。带上气压计和一个量角器来到大楼的顶部,等待太阳到达水平线。然后,把气压计当作镜子,把一束日光引到先前所设定的地点,用量角器测量气压计的角度,然后用三角学原理计算大楼的高度。

比例法:测量气压计的高度。叫一个朋友,并带上一把卷尺。趴在大楼外已知距离的一点,气压计放在你和大楼之间,调整气压计的位置,从你看上去气压计上端正好与楼顶相平。

然后叫你的朋友测量你的眼睛距离气压计的距离,最后根据比例原理计算出大楼的高度。

照相法:从大楼外已知距离的地点支起三角架,架上是照相机。然后把气压计放在与照相机距离已知的地方,拍下照片。根据照片中气压计和大楼的相对高度,你可以计算出大楼的实际高度。

重力法Ⅰ:用长绳系住气压计,从大楼上挂下来直到地面。测量钟摆的摆动时间,根据重力加速度的差别计算出大楼的高度。

重力法Ⅱ:在大楼的顶部和底部分别用弹簧秤测量气压计的重量(不能用天平秤),两个重量应该有所差别,这是由于重力加速度的差异引起的。(一位读者告诉我Lacoste Romberg重力计能够提供准确结果所需要的精度)你可以根据这两个读数计算出大楼的高度。

卡路里法:把气压计从楼顶扔下来,掉到地面一个装有水的容器里。容器的开口应尽量小,尽可能防止水的溅出。水温的升高是气压计的机械能转换为热能的结果,根据水温升高的度数可以计算出气压计到达地面的势能,进一步可以计算出大楼的高度。

你是不是认为这样的问题只会在代数学里出现。

本文摘自《C专家编程》

C/C++程序员工作面试的秘密

C代码。C代码运行。运行码运行…请!
——Barbara Ling
所有的C程序都做同一件事,观察一个字符,然后啥也不干。
——Peter Weinberger

《C专家编程》展示了最优秀的C程序员所使用的编码技巧,并专门开辟了一章对C++的基础知识进行了介绍。

书中C的历史、语言特性、声明、数组、指针、链接、运行时、内存以及如何进一步学习C++等问题进行了细致的讲解和深入的分析。全书撷取几十个实例进行讲解,对C程序员具有非常高的实用价值。

本书可以帮助有一定经验的C程序员成为C编程方面的专家,对于具备相当的C语言基础的程序员,本书可以帮助他们站在C的高度了解和学习C++。

展开阅读全文

页面更新:2024-05-15

标签:程序员   气压计   主考官   楼顶   字符串   指针   建筑物   测量   大楼   元素   高度   答案   秘密   两个   时间   方法   工作   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top