心机婊!一道单选题需要考查这么多知识吗?

转载自微信公众账号:开点工作室(ID:kaidiancs)

阿里2015笔试中有这样一道题目:

在一台主流配置的PC上,调用f(35)所需要的时间大概是()。

int f(int x){

int s = 0;

while(x++ >0)s+= f(x);

return max(s,1);

}

A.几毫秒B.几秒C.几分钟D.几小时

本题涉及到的知识点包括数据的表示和运算、时间复杂度。考查考生对带符号整数的表示、递归调用的执行过程、计算机系统性能、虚拟存储器、C语言语句等相关知识的理解和运用能力。

数学上的分析推导结果与计算机系统中的执行结果是有差异的。例如,在数学中一个数可以无限大,但在计算机中受表示位数的限制,数的值是有限的。用数学分析的方法,本题的递归是可以终止的,但受存储容量的限制,在计算机中递归调用时会有栈溢出的问题,导致程序不能正常执行结束。类似的问题还有很多,这是平时编程时需要注意的。

假设题目中的函数用C语言书写,要分析调用f(35)所需的时间,就得分析代码执行中循环执行次数和递归调用次数等,下面深入剖析f(35)执行过程中存在的问题。

(1)程序是否会终止?

调用f(35)时,入口参数x=35。从数学的角度理解while中的判断表达式“x++ >0”,会认为x在增量后永远大于0,这是一个永真式,从而做出错误结论:程序死循环。在计算机中数值是有范围的,int型数据用补码表示,占4个字节,能表示的最大正数是2-1 = 7FFFFFFFH。231的机器数是8000 0000H,其值为int型能表示的最小负数-2147483648,因此当x= 8000 0000H时,x> 0的值为假,程序退出while循环,因此,若不考虑栈溢出,则程序能执行结束。

(2)使递归终止的最大x值是多少?

while(x++ >0)语句在Microsoft VC中的机器代码如下,该语句的执行过程是:先把x的值分别保存到EDX和EAX寄存器;然后对EAX寄存器内容加1,以实现x=x+1操作;最后再用EDX的内容(x的旧值)进行x>0的条件判断。

mov       edx, dword ptr [ebp+8]

mov        eax,dword ptr [ebp+8]

add        eax, 1

mov       dword ptr [ebp+8], eax

test        edx, edx

jle         f+77h (00401097)

因此,当调用f(231-1)时,x= 231-1=7FFF FFFFH,先执行x=7FFF FFFFH+1 = 8000 0000H=231,然后,用旧的x=7FFF FFFFH与0比较,比较结果为真,故执行while循环体,在循环体中调用f(231)。

调用f(231)时,x为231= 8000 0000H,其真值为负数,因此,与0比较的结果为假,故跳出while循环体,程序结束。

综上所述,使递归终止的最大x值是231,即执行f(231)时结束递归调用。

(3)函数f(x)的递归调用情况如何?

f(x)是一个递归调用过程,并且递归调用在循环体内,因此调用关系较复杂。图1显示了f(231-4)执行中的递归调用情况。

图1f(231-4)执行中的递归调用情况

f(x)执行过程中,把执行f(x)过程体的总次数记为f(x)执行次数,把一次递归调用的最大次数记为f(x)递归深度。表1给出了x为不同值时,执行f(x)的次数和递归深度。这两个参数显示了f(x)函数的执行过程。

(4)递归调用过程的执行情况

系统会给每一个用户进程分配存放代码和数据的用户空间,用户空间中的栈区用来存放程序运行时过程调用的参数、返回地址、过程局部变量等。随着程序的执行,栈区不断动态地从高地址向低地址增长或向反方向减退。

用户栈由若干个栈帧组成,每个过程对应一个栈帧,帧指针寄存器EBP指定一个栈帧的起始地址,栈指针寄存器ESP指向栈顶,当前栈帧的范围在EBP和ESP指向的区域之间。过程执行时,由于不断有数据入栈,所以栈指针ESP会动态移动,而帧指针EBP固定不变。在一个过程内对栈中信息的访问大多通过帧指针EBP进行。

IA-32规定,寄存器EAX、ECX和EDX是调用者保存寄存器,EBX、ESI、EDI寄存器是被调用者保存寄存器。若过程P调用过程Q时,P在需要时先在自己的栈区保存EAX、ECX和EDX、入口参数和返回地址,接着跳转到Q执行。Q在自己的栈帧中先保存P的EBP值,并设置EBP指向当前Q栈帧的栈低,根据需要保存EBX、ESI、EDI,再在栈中给Q的局部变量分配空间。

在递归调用执行中,每个递归调用过程都有一个栈帧。栈帧中可能包含如图2所示的信息。

图3显示了在windows系统中f(x)函数调用时的部分机器指令。可以看出f(x)的栈帧至少有84B。系统分配给一个进程的用户栈只有有限的空间,因此,递归调用的次数是有限的。f(35)的递归深度是2147483614,即至少需要2147483614×84字节,即大于170GB的栈帧空间。在32位系统中,最大虚拟地址空间仅有4GB,用户栈只是其中的一部分,所以f(35)在执行过程中会出现栈溢出的现象。

图3 f(x)函数调用时的部分机器指令

(5)f(35)在32位系统中的实际执行情况

假设在Intel x86+windows+VC+C语言环境中执行f(35)。VC中默认分配栈的大小是1MB,虽然用户可以调整栈大小,但栈的容量是有限的。按2MB的栈空间、栈大小按80字节计算:2MB÷80B≈26214,因此f(x)递归调用的次数不会超过26214-1=26213次。从图4.9中可以看出,栈溢出时,f(x)函数体最多执行26213次。栈溢出时每个f(x)函数体只在while语句中执行,假设每个f(x)函数体执行100条指令,即使指令平均CPI为3,时钟频率为2.4GHz,f(35)的执行时间也只有26213×100×3÷2.4GHz ≈3.2 ms左右时间。

f(35)的执行做了测试,在栈大小是1MB时,递归调用11244次后栈溢出;在栈设置为2MB时,递归调用22642次后栈溢出,显然运行时间只有几毫秒。在Microsoft VisualStudio 2012环境中运行,出现如图4所示结果,表明出现了栈溢出(Stack overflow)。

综上所述,答案为A。

由此可以看出,虽然该题只是一道简单的选择题,其中蕴藏着的背景知识却非常丰富,该题完全可以变换成一道面试中的综合题目,考查应聘者是否能够熟悉相关的背景知识,并且能够根据这些基础知识进行合理有效的分析。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容

  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 4,591评论 1 19
  • 站在巨人的肩膀上——IDA PRO权威指南阅读笔记 一,窗口 view->open subviews 打开/关闭各...
    SueLyon阅读 14,366评论 0 6
  • Exercise 3 方法:打开终端运行make qemu-gdb,再打开另一个终端运行make gdb,通过b ...
    找不到工作阅读 10,039评论 0 6
  • 传说很久以前,一栋废弃的古宅里住着一个魔王。那个魔王手下有一群鬼手下。他们都很残暴,凶狠,没有人敢侵犯他们的领地。...
    阿布大阅读 604评论 0 1
  • 世上从无感同身受。 1. 夜里做了一个很不友好的梦。 出门时差点踩到死老鼠。 储在公司的干粮被老鼠消灭殆尽,饱暖思...
    青瓷白话阅读 593评论 5 0