單片機面試筆試大全_第1頁
單片機面試筆試大全_第2頁
單片機面試筆試大全_第3頁
單片機面試筆試大全_第4頁
單片機面試筆試大全_第5頁
已閱讀5頁,還剩30頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

.單片機筆試面試白皮書目錄第一部筆試面試流程1一、準備簡歷1二、簡歷投遞2三、筆試準備2四、面試準備3五、面試練習(xí)4第二部C筆試面試題4第一大塊:根本語法4第二大塊:變量6第三大塊:函數(shù)14第四大塊:指針&存17第五大塊:鏈表22第六大塊:算法25第三部LSD筆試面試題31第四部C++/驅(qū)動筆試面試題32第五部JAVA筆試面試題34第六部android筆試面試題34第七部工程面試題35第一部筆試面試流程一、準備簡歷在51、智聯(lián)、中華英才個做一份簡歷。簡歷容重點:所學(xué)課程〔C語言、linu*系統(tǒng)程序設(shè)計、JAVA、android〕所做工程:工程描述一定要完整,清晰。工程是關(guān)鍵點。并且,如果面試的是android,則把android工程放在前面?!疽痪湓挃[平】你和應(yīng)屆生的本質(zhì)區(qū)別,就在于你有工程經(jīng)歷。工作背景:如果有技術(shù)相關(guān)背景,寫清楚,只要技術(shù)相關(guān)都可以加分的。交流背景:以前做過和交流溝通相關(guān)的事情如果是應(yīng)屆生,則做過的學(xué)生會工作,組著過活動等;如果工作過,則做過的工作,把閃光點說出來;最起碼,工作溝通、穩(wěn)定性等方面是可以展示出來的。面試官很關(guān)心這個。簡歷書寫考前須知:.簡歷書寫語言簡潔,多用條例性語言。〔第一、第二、第三、...〕簡歷不能出現(xiàn)經(jīng)歷空白,如中間半年沒有任何經(jīng)歷。簡歷不能和其他學(xué)員的簡歷出現(xiàn)一樣的容,尤其是工程描述。否則,兩個人都有可能失去面試時機。簡歷版面簡單,字體不要超過3種。不需要相片,不需要花哨的格式。招聘介紹:51效果最好,重點關(guān)注51招聘。注意關(guān)鍵字:在簡歷重要多出現(xiàn)重要關(guān)鍵字:C語言、數(shù)據(jù)構(gòu)造、linu*系統(tǒng)開發(fā)〔linu*系統(tǒng)移植、驅(qū)動、arm、C++〕、JAVA、android二、簡歷投遞每天早晨〔一定要早晨,早晨的效果是最好的,否則可能效果減半〕把3個的簡歷都“刷新〞一下。每天早晨投遞簡歷,主要搜索,嵌入式開發(fā)、C開發(fā)、linu*開發(fā)、JAVA開發(fā)、android開發(fā)、軟件開發(fā)。每天投遞十幾個公司。一家公司,如果沒給面試通知,屢次投遞。重點關(guān)注的51,要在這個上注冊2-3個賬號,使用同樣的簡歷,每天可以更換賬號投遞。并不是你投遞的每個人的簡歷公司人事都會看到,如果收到的簡歷很多,則人事可能每天只能看到排在收件箱最前面的簡歷。所以你的投遞必須要人事能最先看到。簡歷投遞的重點注意:第一、最好投遞時間是早晨。早晨效果往往是其他時間段的兩倍。第二、51上要注冊兩、三個賬號。使用同樣的簡歷,輪流投遞。第三、第一輪投遞使用海投的方式,即搜索“嵌入式開發(fā)〞、“l(fā)inu*開發(fā)〞、“C開發(fā)〞等關(guān)鍵字,然后全選投遞〔海投〕。第四、以后每天堅持投遞,投遞職位數(shù)目在十多個。三、筆試準備筆試的主要容應(yīng)該是C語言和android,其次算法,JAVA。所以C語言必須扎實。很多公司的筆試題目就是為了筆試而筆試,可能開發(fā)中千年難用。但是你做不出來,就能表達出公司的出題水平。我們可以鄙視這些公司,但我們還是要認真準備筆試的。1、“嵌入式經(jīng)典筆試整理收錄〞這份題目必須看.這里面的題目一道都不能落下全部弄懂。這里面都是根底.包括概念在.練習(xí)題目不但要看懂,而且要在紙上動手寫出來。一定要在紙上寫出來,因為不筆試的時候不是上機,要一次寫出來,難度還是大些。2、“高質(zhì)量C++-C編程指南.doc〞看這份資料。這份看完根本C語言就沒有太多問題。3、看其他面試筆試資料。資料要多看。注意:很多筆試題目一定要自己在紙上寫出來。筆試講求的就是“紙上談兵〞!在紙上寫程序要比你在電腦上寫難很多。切記不可以驕傲。.四、面試準備看"嵌入式經(jīng)典面試題目收錄"常見面試題目。必須每道題目都能流暢完整打出來。準備自我介紹:1、教育背景:學(xué)校專業(yè)畢業(yè)時間。2、工作背景:之前從事什么工作。一定要說明為什么轉(zhuǎn)到這個行業(yè)了,為什么離開上一家公司了。對之前工作中的自己不要否認:因為你自己都否認自己了,誰還會肯定你?3、培訓(xùn)背景:所學(xué)課程:課程名稱(不要把課程名稱都忘掉了,名字都忘了,別人怎么相信你學(xué)好這個課程〕所做工程:在培訓(xùn)期間動手完成了那些工程。工程描述要清晰,一般套路:1、工程名稱〔這個也不能忘〕2、工程簡介3、工程分成幾個模塊4、工程所使用的技術(shù)。工程描述是整個面試的一個重點。4、技術(shù)問答:對面試官所提出的技術(shù)問題,進展解答。解答問題要簡潔明了,要用肯定語氣,一定要給面試官信心?;氐絾栴}要簡介明了,不要有語氣詞。如果有不會答復(fù)的問題,不用著急??梢钥隙ǖ母嬖V面試官不知道。很多問題答不上來是正常的。所以不要緊。都答上來還不一定要你呢〔面試中面試官一定要出一些擬答不上來的問題,這樣才能確定你的能力圍,另外也能讓你認識到自己的缺乏,這樣你開價的時候也會自覺地悠著點〕。也可以繞過去,但不能太多問題都去繞。面試官提問喜歡沿著一個問題不停的追問,直到你不會為止。所以準備的時候注意一定要全面深入。另外不會也不用緊,影響后面的面試。5、人事面試:常見問題:你對加班的看法?你對你上一家公司的經(jīng)理的看法?你覺得你最忌最大的優(yōu)點和缺點個是什么?你為什么離開上一家公司?你3年或者5年的職業(yè)開展規(guī)劃?你覺得你自己值這么多錢〔你開的薪資〕嗎?閑聊:注意閑聊的時候不要忘形,要給別人一種穩(wěn)定,喜歡技術(shù),對公司所屬行業(yè)感興趣,自己個人愛好安康,不要提消極〔愛玩游戲,懶,之類的事情〕6、談薪資:談薪資,開場要想要自己期望的薪資是多少。不要模糊的。告訴比人我期望薪資多少。不過不要太高,如果太高的話,別人即使想要你也可以去,但別人會認為你不踏實,而不敢要你。所以你所說的期望薪資可以比你的最低薪資多出500.最多不能多出1000.注意一般面試時間要超過20分鐘。如果面試官面試時間超過20分鐘,則說明他對你的情趣比擬大了。30分鐘以上說明你已經(jīng)有6成以上的把握了。一般情況如果面試的人當時沒有對你表示出意向,讓你回去等通知,根本沒戲了。.五、面試練習(xí)把面試的自我介紹寫下來,讓后多讀幾遍。最好是對著鏡子讀。不要不好意思,流暢與否,那就是每月500或者1000的差呀。。。面試準備是非常重要的。因為經(jīng)常面試的東西主要就那些。另外,面試過程中必須對自己有信心。那怕裝也得裝出來。正常情況下,如果兩個人技術(shù)差不多,則面試官一般都會挑選有信心的。有信心的人在日后的工程中會更有韌性,能擔當?shù)母?。即使技術(shù)現(xiàn)在不是很好,但有信心的話,可以在以后的工作中很快就彌補上來了。每個人對自己的信心,要有這樣的覺悟,即使我現(xiàn)在技術(shù)不是很好,但我將來一定會好好學(xué),好好做,一定能給我所在的公司帶來價值,公司選擇我那是正確,不選我那是公司最大的損失。反過來,如果對自己沒有信心,那憑什么讓面試官對你有信心呢?即使你技術(shù)過了,他還可能認為,是不是死記硬背的。即使你值5k他會覺得,給你3.5k你都會來。面試不但是技術(shù)的戰(zhàn)爭,更是心理的戰(zhàn)爭。最后一句:信心十足,但不高調(diào)。祝大家馬到成功!?。〉诙緾筆試面試題第一大塊:根本語法用預(yù)處理指令#define聲明一個常數(shù),用以說明1年中有多少秒〔忽略閏年問題〕#defineSECONDS_PER_YEAR(60*60*24*365)UL我在這想看到幾件事情:1).#define語法的根本知識〔例如:不能以分號完畢,括號的使用,等等〕2).懂得預(yù)處理器將為你計算常數(shù)表達式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。3).意識到這個表達式將使一個16位機的整型數(shù)溢出-因此要用到長整型符號L,告訴編譯器這個常數(shù)是的長整型數(shù)。4).如果你在你的表達式中用到UL〔表示無符號長整型〕,則你有了一個好的起點。記住,第一印象很重要。寫一個“標準〞宏MIN,這個宏輸入兩個參數(shù)并返回較小的一個#defineMIN(A,B)((A)<=(B)(A):(B))這個測試是為下面的目的而設(shè)的:1).標識#define在宏中應(yīng)用的根本知識。這是很重要的,因為直到嵌入(inline)操作符變?yōu)闃藴蔆的一局部,宏是方便產(chǎn)生嵌入代碼的唯一方法,對于嵌入式系統(tǒng)來說,為了能到達要求的性能,嵌入代碼經(jīng)常是必須的方法。2).三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產(chǎn)生比if-then-else更優(yōu)化的代碼,了解這個用法是很重要的。3).懂得在宏中小心地把參數(shù)用括號括起來4).我也用這個問題開場討論宏的副作用,例如:當你寫下面的代碼時會發(fā)生什么事?least=MIN(*p++,b);其實宏在編程中的副作用主要表現(xiàn)在編譯器的處理計算上,如果考慮不周全很容易出現(xiàn)重復(fù)計算的問題。所以寫程序要用宏的簡潔,又要注意其中的陷阱,以防出現(xiàn)莫名其妙.的錯誤用宏定義寫出swap(*,y)#defineswap(*,y)\*=*+y;\y=*-y;\*=*-y;請定義一個宏,比擬兩個數(shù)a、b的大小,不能使用大于、小于、if語句#defineMa*(a,b)(a/b)“a:b預(yù)處理器標識#error的目的是什么“如果你不知道答案,直接baidu。字節(jié)對齊//#pragmapack(4)structst{charc;inti;shorts;};sizeof(structst);死循環(huán)〔Infiniteloops〕嵌入式系統(tǒng)中經(jīng)常要用到無限循環(huán),你怎么樣用C編寫死循環(huán)呢“這個問題用幾個解決方案。我首選的方案是:while(1){}一些程序員更喜歡如下方案:for(;;){}這個實現(xiàn)方式讓我為難,因為這個語法沒有確切表到達底怎么回事。如果一個應(yīng)試者給出這個作為方案,我將用這個作為一個時機去探究他們這樣做的根本原理。如果他們的根本答案是:“我被教著這樣做,但從沒有想到過為什么。〞這會給我留下一個壞印象。第三個方案是用gotoLoop:...gotoLoop;應(yīng)試者如給出上面的方案,最好解釋匯編語言程或BASIC/FORTRAN語言可以這么做。但如果是C編程中出現(xiàn)goto,則會留下惡劣的印象。Typedef在C語言中頻繁用以聲明一個已經(jīng)存在的數(shù)據(jù)類型的同義字。也可以用預(yù)處理器做類似的事。例如,思考一下下面的例子:#definedPSstructs*typedefstructs*tPS;.dPSmm,qq;//structs*mm,qq;tPSnn,pp;//structs*mm,*qq;以上兩種情況的意圖都是要定義dPS和tPS作為一個指向構(gòu)造s指針。哪種方法更好呢?〔如果有的話〕為什么?這是一個非常微妙的問題,任何人答對這個問題〔正當?shù)脑颉呈菓?yīng)當被恭喜的。答案是:typedef更好。思考下面的例子:dPSp1,p2;tPSp3,p4;第一個擴展為structs*p1,p2;上面的代碼定義p1為一個指向構(gòu)造的指,p2為一個實際的構(gòu)造,這也許不是你想要的。第二個例子正確地定義了p3和p4兩個指針。C語言同意一些令人震驚的構(gòu)造,下面的構(gòu)造是合法的嗎,如果是它做些什么?inta=5,b=7,c;c=a+++b;這個問題將做為這個測驗的一個愉快的結(jié)尾。不管你相不相信,上面的例子是完全符合語法的。問題是編譯器如何處理它?水平不高的編譯作者實際上會爭論這個問題,根據(jù)最處理原則,編譯器應(yīng)當能處理盡可能所有合法的用法。因此,上面的代碼被處理成:c=a+++b;因此,這段代碼持行后a=6,b=7,c=12。頭文件中的ifndef/define/endif干什么用“一個死循環(huán)intmain〔〕{unsignedchari;for〔i=0;i<256;i++〕{printf(“i=%d\n〞,i);}return0;}程序運行結(jié)果如何輸出源文件的標題和目前執(zhí)行行的行數(shù)intline=__LINE__;char*file=__FILE__;cout<<"filenameis"<<(file)<<",lineis"<第二大塊:變量變量的存儲空間C程序一直由以下局部組成:〔1〕正文段——CPU執(zhí)行的機器指令局部;一個程序只有一個副本;只讀,防止程序由于意外事故而修改自身指令;〔2〕初始化數(shù)據(jù)段〔數(shù)據(jù)段〕——在程序中所有賦了初值的全局變量,存放在這里?!?〕非初始化數(shù)據(jù)段〔bss段〕——在程序中沒有初始化的全局變量;核將此段初始化.為0?!?〕?!鲩L方向:自頂向下增長;自動變量以及每次函數(shù)調(diào)用時所需要保存的信息〔返回地址;環(huán)境信息〕?!?〕堆——動態(tài)存儲分配。|--------------|高地址|--------------||棧||--------------|||||\|/||/|\|||||--------------||堆||--------------||未初始化||--------------||初始化||--------------||正文段|低地址問題:局部變量存放區(qū)域?初始化全局變量存放區(qū)域?未初始化的全局變量存放區(qū)域?靜態(tài)局部變量存放區(qū)域?動態(tài)分配存是在那個區(qū)域?堆和棧的區(qū)別【一句話擺平】堆是手動,但容易導(dǎo)致存碎片;棧是自動,但空間有限。一般認為在c中分為這幾個存儲區(qū)(1)、棧-有編譯器自動分配釋放(2)、堆-一般由程序員分配釋放,假設(shè)程序員不釋放,程序完畢時可能由OS回收(3)、全局區(qū)〔靜態(tài)區(qū)〕,全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。-程序完畢釋放(4)、另外還有一個專門放常量的地方。-程序完畢釋放在函數(shù)體中定義的變量通常是在棧上,用malloc,calloc,realloc等分配存的函數(shù)分配得到的就是在堆上。在所有函數(shù)體外定義的是全局量,加了static修飾符后不管在哪里都存放在全局區(qū)〔靜態(tài)區(qū)〕,在所有函數(shù)體外定義的static變量表示在該文件中有效,不能e*tern到別的文件用,在函數(shù)體定義的static表示只在該函數(shù)體有效。另外,函數(shù)中的"adgfdf"這樣的字符串存放在常量區(qū)。比方:inta=0;全局初始化區(qū)char*p1;全局未初始化區(qū)main(){intb;棧chars[]="abc";棧char*p2;棧char*p3="123456";123456\0在常量區(qū),p3在棧上。staticintc=0;全局〔靜態(tài)〕初始化區(qū)p1=(char*)malloc(10);p2=(char*)malloc(20);分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。strcpy(p1,"123456");123456\0放在常量區(qū),編譯器可能會將它與p3所指向的"12345.6"優(yōu)化成一塊。}還有就是函數(shù)調(diào)用時會在棧上有一系列的保存現(xiàn)場及傳遞參數(shù)的操作。棧的空間大小有限定,vc的缺省是2M。棧不夠用的情況一般是程序中分配了大量數(shù)組和遞歸函數(shù)層次太深。有一點必須知道,當一個函數(shù)調(diào)用完返回后它會釋放該函數(shù)中所有的??臻g。棧是由編譯器自動管理的,不用你操心。堆是動態(tài)分配存的,并且你可以分配使用很大的存。但是用不好會產(chǎn)生存泄漏。并且頻繁地malloc和free會產(chǎn)生存碎片〔有點類似磁盤碎片〕,因為c分配動態(tài)存時是尋找匹配的存的。而用棧則不會產(chǎn)生碎片。在棧上存取數(shù)據(jù)比通過指針在堆上存取數(shù)據(jù)快些。一般大家說的堆棧和棧是一樣的,就是棧(stack),而說堆時才是堆heap.棧是先入后出的,一般是由高地址向低地址生長。堆(heap)和棧(stack)是C/C++/JAVA編程不可防止會碰到的兩個根本概念。首先,這兩個概念都可以在講數(shù)據(jù)構(gòu)造的書中找到,他們都是根本的數(shù)據(jù)構(gòu)造,雖然棧更為簡單一些。在具體的C/C++/JAVA編程框架中,這兩個概念并不是并行的。對底層機器代碼的研究可以提醒,棧是機器系統(tǒng)提供的數(shù)據(jù)構(gòu)造,而堆則是C/C++/JAVA函數(shù)庫提供的。具體地說,現(xiàn)代計算機(串行執(zhí)行機制),都直接在代碼底層支持棧的數(shù)據(jù)構(gòu)造。這表達在,有專門的存放器指向棧所在的地址,有專門的機器指令完成數(shù)據(jù)入棧出棧的操作。這種機制的特點是效率高,支持的數(shù)據(jù)有限,一般是整數(shù),指針,浮點數(shù)等系統(tǒng)直接支持的數(shù)據(jù)類型,并不直接支持其他的數(shù)據(jù)構(gòu)造。因為棧的這種特點,對棧的使用在程序中是非常頻繁的。對子程序的調(diào)用就是直接利用棧完成的。機器的call指令里隱含了把返回地址推入棧,然后跳轉(zhuǎn)至子程序地址的操作,而子程序中的ret指令則隱含從堆棧中彈出返回地址并跳轉(zhuǎn)之的操作。C/C++/JAVA中的自動變量是直接利用棧的例子,這也就是為什么當函數(shù)返回時,該函數(shù)的自動變量自動失效的原因(因為顏換指戳說饔們暗狀態(tài))。和棧不同,堆的數(shù)據(jù)構(gòu)造并不是由系統(tǒng)(無論是機器系統(tǒng)還是操作系統(tǒng))支持的,而是由函數(shù)庫提供的。根本的malloc/realloc/free函數(shù)維護了一套部的堆數(shù)據(jù)構(gòu)造。當程序使用這些函數(shù)去獲得新的存空間時,這套函數(shù)首先試圖從部堆中尋找可用的存空間,如果沒有可以使用的存空間,則試圖利用系統(tǒng)調(diào)用來動態(tài)增加程序數(shù)據(jù)段的存大小,新分配得到的空間首先被組織進部堆中去,然后再以適當?shù)男问椒祷亟o調(diào)用者。當程序釋放分配的存空間時,這片存空間被返回部堆構(gòu)造中,可能會被適當?shù)奶幚?比方和其他空閑空間合并成更大的空閑空間),以更適合下一次存分配申請。這套復(fù)雜的分配機制實際上相當于一個存分配的緩沖池(Cache),使用這套機制有如下假設(shè)干原因:1.系統(tǒng)調(diào)用可能不支持任意大小的存分配。有些系統(tǒng)的系統(tǒng)調(diào)用只支持固定大小及其倍數(shù)的存請求(按頁分配);這樣的話對于大量的小存分類來說會造成浪費。2.系統(tǒng)調(diào)用申請存可能是代價昂貴的。系統(tǒng)調(diào)用可能涉及用戶態(tài)和核心態(tài)的轉(zhuǎn)換。3.沒有管理的存分配在大量復(fù)雜存的分配釋放操作下很容易造成存碎片。堆和棧的比照從以上知識可知,棧是系統(tǒng)提供的功能,特點是快速高效,缺點是有限制,數(shù)據(jù)不靈活;而棧是函數(shù)庫提供的功能,特點是靈活方便,數(shù)據(jù)適應(yīng)面廣泛,但是效率有一定降低。棧是系統(tǒng)數(shù)據(jù)構(gòu)造,對于進程/線程是唯一的;堆是函數(shù)庫部數(shù)據(jù)構(gòu)造,不一定唯一。不同堆分配的存無法互相操作。??臻g分靜態(tài)分配和動態(tài)分配兩種。靜態(tài)分配是編譯器完成的,比方自動變量(auto)的分配。動態(tài)分配由alloc函數(shù)完成。棧的動態(tài)分配無需釋放(是自動的),也就沒有釋放函數(shù)。為可移植的程序起見,棧的動態(tài)分配操作是不被鼓勵的!堆空間的分配總是動態(tài)的,雖然程序完畢時所有的數(shù)據(jù)空間都會被釋放回系統(tǒng),但是準確的申請存/釋放存匹配是良好程序的根本要素。所以計算機中的堆和棧經(jīng)常時放一塊講的node一般不是必要就不要動態(tài)創(chuàng)立,最討厭是,C++中,把new出來的東西當局部變量用,用完了馬上delete的做法;最惡劣的是,JAVA中不斷地new,然后等著GC來回收。理由1.棧分配比堆快,只需要一條指令就呢給配所有的局部變量2.棧不會出現(xiàn)存碎片3.棧對象好管理當然,*些情況下也要則寫,比方1.對象很大2.對象需要在*個特定的時刻構(gòu)造或.析夠3.類只允許對象動態(tài)創(chuàng)立,比方VCL的大多數(shù)類當然,必須用堆對象時也不能躲避對于類的申明〔還沒有定義〕來說,可以有限的方式使用它。如我們可以聲明指向該類類型的指針或引用。允許指針和引用是因為它們都有固定的大小,而與它們指向的對象的大小無關(guān)。只有到完全定義了該類才能對這些指針和引用解引用。只有對類定義了,才能聲明該類類型對象。在程序中還沒有看到類定義之前,數(shù)據(jù)成員只能是該類類型的指針或引用。當一個類的類頭被看到時,它就被視為已經(jīng)聲明了,所以一個類可以有指向自身類型的指針或引用作為數(shù)據(jù)成員。只有一個類的類體已經(jīng)完整時,它才被視為已經(jīng)被定義。所以可以有如下形式:classLinkScreen{Screenwindow;LinkScreen*ne*t;LinkScreen*prev;}關(guān)鍵字static的作用是什么?這個簡單的問題很少有人能答復(fù)完全。在C語言中,關(guān)鍵字static有三個明顯的作用:1).在函數(shù),一個被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。2).在模塊〔但在函數(shù)外〕,一個被聲明為靜態(tài)的變量可以被模塊所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個本地的全局變量。3).在模塊,一個被聲明為靜態(tài)的函數(shù)只可被這一模塊的其它函數(shù)調(diào)用。那就是,這個函數(shù)被限制在聲明它的模塊的本地圍使用。大多數(shù)應(yīng)試者能正確答復(fù)第一局部,一局部能正確答復(fù)第二局部,同是很少的人能懂得第三局部。這是一個應(yīng)試者的嚴重的缺點,因為他顯然不懂得本地化數(shù)據(jù)和代碼圍的好處和重要性。靜態(tài)變量(1)、靜態(tài)全局變量在全局變量前,加上關(guān)鍵字static,該變量就被定義成為一個靜態(tài)全局變量。靜態(tài)全局變量有以下特點:該變量在全局數(shù)據(jù)區(qū)分配存;未經(jīng)初始化的靜態(tài)全局變量會被程序自動初始化為0〔自動變量的值是隨機的,除非它被顯式初始化〕;靜態(tài)全局變量在聲明它的整個文件都是可見的,而在文件之外是不可見的;靜態(tài)變量都在全局數(shù)據(jù)區(qū)分配存,包括后面將要提到的靜態(tài)局部變量。對于一個完整的程序代碼區(qū)全局數(shù)據(jù)區(qū)堆區(qū)棧區(qū)一般程序的由new產(chǎn)生的動態(tài)數(shù)據(jù)存放在堆區(qū),函數(shù)部的自動變量存放在棧區(qū)。自動變量一般會隨著函數(shù)的退出而釋放空間,靜態(tài)數(shù)據(jù)〔即使是函數(shù)部的靜態(tài)局部變量〕也存放在全局數(shù)據(jù)區(qū)。全局數(shù)據(jù)區(qū)的數(shù)據(jù)并不會因為函數(shù)的退出而釋放空間。確實,定義全局變量就可以實現(xiàn)變量在文件中的共享,但定義靜態(tài)全局變量還有以下好處:靜態(tài)全局變量不能被其它文件所用;其它文件中可以定義一樣名字的變量,不會發(fā)生沖突;(2)、靜態(tài)局部變量【一句話解決】靜態(tài)局部變量具有記憶性在局部變量前,加上關(guān)鍵字static,該變量就被定義成為一個靜態(tài)局部變量。通常,在函數(shù)體定義了一個變量,每當程序運行到該語句時都會給該局部變量分配棧存。但隨著程序退出函數(shù)體,系統(tǒng)就會收回棧存,局部變量也相應(yīng)失效。但有時候我們需要在兩次調(diào)用之間對變量的值進展保存。通常的想法是定義一個全局變量來實現(xiàn)。但這樣一來,變量已經(jīng)不再屬于函數(shù)本身了,不再僅受函數(shù)的控制,給程序的維護帶來不便。靜態(tài)局部變量正好可以解決這個問題。靜態(tài)局部變量保存在全局數(shù)據(jù)區(qū),而不是保存在棧中,每次的值保持到下一次調(diào)用,直到下次賦新值。e*ample:voidfoo(){staticinta;a++;.cout<<a<<endl;//C++語法,和C語言中的printf類似}intmain(){foo();foo();foo();return0;}結(jié)果是123每次foo〔〕退出后,并未銷毀變量a,因為它是存放在全局數(shù)據(jù)區(qū)的,不是棧空間。靜態(tài)局部變量有以下特點:該變量在全局數(shù)據(jù)區(qū)分配存;靜態(tài)局部變量在程序執(zhí)行到該對象的聲明處時被首次初始化,即以后的函數(shù)調(diào)用不再進展初始化;靜態(tài)局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程序自動初始化為0;它始終駐留在全局數(shù)據(jù)區(qū),直到程序運行完畢。但其作用域為局部作用域,當定義它的函數(shù)或語句塊完畢時,其作用域隨之完畢;18.關(guān)鍵字const是什么含意?只要一聽到被面試者說:“const意味著常數(shù)〞,我就知道我正在和一個業(yè)余者打交道。constinta;intconsta;constint*a;int*consta;intconst*a;前兩個的作用是一樣,a是一個常整型數(shù)。第三個意味著a是一個指向常整型數(shù)的指針〔也就是,整型數(shù)是不可修改的,但指針可以〕。第四個意思a是一個指向整型數(shù)的常指針〔也就是說,指針指向的整型數(shù)是可以修改的,但指針是不可修改的〕。最后一個意味著a是一個指向常整型數(shù)的常指針〔也就是說,指針指向的整型數(shù)是不可修改的,同時指針也是不可修改的〕。如果應(yīng)試者能正確答復(fù)這些問題,則他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關(guān)鍵字const,也還是能很容易寫出功能正確的程序,則我為什么還要如此看重關(guān)鍵字const呢?我也如下的幾下理由:1).關(guān)鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數(shù)為常量是為了告訴了用戶這個參數(shù)的應(yīng)用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學(xué)會感這點多余的信息。〔當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的?!?).通過給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。3).合理地使用關(guān)鍵字const可以使編譯器很自然地保護那些不希望被改變的參數(shù),防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現(xiàn)。關(guān)鍵字volatile有什么含意并給出三個不同的例子//register一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。準確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在存放器里的備份。下面是volatile變量的幾個例子:1).并行設(shè)備的硬件存放器〔如:狀態(tài)存放器〕2).一個中斷效勞子程序中會訪問到的非自動變量(Non-automaticvariables)3).多線程應(yīng)用中被幾個任務(wù)共享的變量答復(fù)不出這個問題的人是不會被雇傭的。我認.為這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最根本的問題。嵌入式系統(tǒng)程序員經(jīng)常同硬件、中斷、RTOS等等打交道,所用這些都要求volatile變量。不懂得volatile容將會帶來災(zāi)難。假設(shè)被面試者正確地答復(fù)了這是問題〔嗯,疑心這否會是這樣〕,我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。1).一個參數(shù)既可以是const還可以是volatile嗎?解釋為什么。2).一個指針可以是volatile嗎?解釋為什么。3).下面的函數(shù)有什么錯誤:intsquare(volatileint*ptr){return*ptr**ptr;}下面是答案:1).是的。一個例子是只讀的狀態(tài)存放器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應(yīng)該試圖去修改它。2).是的。盡管這并不很常見。一個例子是當一個中效勞子程序修該一個指向一個buffer的指針時。3).這段代碼的有個惡作劇。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:intsquare(volatileint*ptr){inta,b;a=*ptr;b=*ptr;returna*b;}由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結(jié)果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:longsquare(volatileint*ptr){inta;a=*ptr;returna*a;}下面的代碼輸出的是什么?為什么?voidfoo(void){unsignedinta=6;intb=-20;(a+b>6)“puts(">6"):puts("<=6");}這個問題測試你是否懂得C語言中的整數(shù)自動轉(zhuǎn)換原則,我發(fā)現(xiàn)有些開發(fā)者懂得極少這些東西。不管如何,這無符號整型問題的答案是輸出是“>6〞。原因是當表達式中存在有符號類型和無符號類型時所有的操作數(shù)都自動轉(zhuǎn)換為無符號類型。因此-20變成了一個非常大的正整數(shù),所以該表達式計算出的結(jié)果大于6。這一點對于應(yīng)當頻繁用到無符號數(shù)據(jù)類型的嵌入式系統(tǒng)來說是豐常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。位操作〔Bitmanipulation〕位操作.嵌入式系統(tǒng)總是要用戶對變量或存放器進展位操作。給定一個整型變量a,寫兩段代碼,第一個設(shè)置a的bit3,第二個去除a的bit3。在以上兩個操作中,要保持其它位不變。對這個問題有三種根本的反響1).不知道如何下手。該被面者從沒做過任何嵌入式系統(tǒng)的工作。2).用bitfields。Bitfields是被扔到C語言死角的東西,它保證你的代碼在不同編譯器之間是不可移植的,同時也保證了的你的代碼是不可重用的。我最近不幸看到Infineon為其較復(fù)雜的通信芯片寫的驅(qū)動程序,它用到了bitfields因此完全對我無用,因為我的編譯器用其它的方式來實現(xiàn)bitfields的。從道德講:永遠不要讓一個非嵌入式的家伙粘實際硬件的邊。3).用#defines和bitmasks操作。這是一個有極高可移植性的方法,是應(yīng)該被用到的方法。最正確的解決方案如下:#defineBIT3(0*1<<3)//00001000staticinta;voidset_bit3(void){a|=BIT3;}voidclear_bit3(void){a&=~BIT3;//10011011&=11110111//a=10010011}一些人喜歡為設(shè)置和去除值而定義一個掩碼同時定義一些說明常數(shù),這也是可以承受的。我希望看到幾個要點:說明常數(shù)、|=和&=~操作。訪問固定的存位置〔Accessingfi*edmemorylocations〕評價下面的代碼片斷:unsignedintzero=0;unsignedintpzero=0*FFFF;/*1'splementofzero*/對于一個int型不是16位的處理器為說,上面的代碼是不正確的。應(yīng)編寫如下:unsignedintpzero=~0;這一問題真正能揭露出應(yīng)試者是否懂得處理器字長的重要性。在我的經(jīng)歷里,好的嵌入式程序員非常準確地明白硬件的細節(jié)和它的局限,然而PC機程序往往把硬件作為一個無法防止的煩惱。到了這個階段,應(yīng)試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應(yīng)試者不是很好,則這個測試就在這里完畢了。但如果顯然應(yīng)試者做得不錯,則我就扔出下面的追加問題,這些問題是比擬難的,我想僅僅非常優(yōu)秀的應(yīng)試者能做得不錯。提出這些問題,我希望更多看到應(yīng)試者應(yīng)付問題的方法,而不是答案。不管如何,你就當是這個娛樂吧…#include<stdio.h>#include<stdlib.h>intmain(void){unionA{chara;chary:3;.charz:3;char*:2;}a;a.a=0*67;printf("a.a=%0*a.*=%0*\ta.y=%0*\ta.z=%0*\n",a.a,a.*,a.y,a.z);return0;}結(jié)果a.a=67a.*=ffffffffa.y=ffffffffa.z=ffffffff=64a.*=0a.y=fffffffca.z=fffffffca.a=65a.*=1a.y=fffffffda.z=fffffffd如果單從位域來理解這個還是簡單,問題的關(guān)鍵是理解其在計算機的存取規(guī)則。對a.a=64,單從取位(二進制)上可知a.*=00,a.y=101,a.z=101.目前通用計算機*86大都是32位機,我的機器也是32位,在存取上默認是存取32位。對每個數(shù)而言第一位是符號位,補碼存儲。則可以理解a.*的補碼就是00000000,a.y的補碼就是11111100,a.z的補碼就是11111100.這樣看比擬自然,但如果輸出結(jié)果是10進制,就會覺得難以理解。當然關(guān)鍵還是對數(shù)據(jù)的存取規(guī)則和編碼的熟悉。a.a=0*64的10進制結(jié)果是a.*=0,a.y=-4,a.z=-4補充一點,union的變量順序?qū)Y(jié)果不影響〔每次只可能有一種解釋是合理的,這個跟struct顯然不同〕2、關(guān)于位域在構(gòu)造體的應(yīng)用主要要注意存對齊規(guī)則的理解和空域的理解使用位域的主要目的是壓縮存儲,其大致規(guī)則為:1)如果相鄰位域字段的類型一樣,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止;2)如果相鄰位域字段的類型一樣,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開場,其偏移量為其類型大小的整數(shù)倍;3)如果相鄰的位域字段的類型不同,則各編譯器的具體實現(xiàn)有差異,VC6采取不壓縮方式,Dev-C++采取壓縮方式;4)如果位域字段之間穿插著非位域字段,則不進展壓縮;5)整個構(gòu)造體的總大小為最寬根本類型成員大小的整數(shù)倍。#include<stdio.h>intmain(){union{struct{unsignedshorts1:3;unsignedshorts2:3;unsignedshorts3:3;}*;charc;}v;v.c=100;printf("%d\n",sizeof(v));printf("s1=%d\n",v.*.s1);.printf("s2=%d\n",v.*.s2);printf("s3=%d\n",v.*.s3);return0;}fc6--linu*下gcc-4.1.12s1=4s2=4s3=50010001100100windows*p2下vc6.02s1=4s2=4s3=1可見s3的結(jié)果并不一樣vc6.0的結(jié)果如果只是按位取,就很好理解,這樣跟之前的union的存取規(guī)則又不一樣了~~而對于,s3=5還沒想出該結(jié)果的原因。同時考慮struct{unsignedshorts1:3;unsignedshorts2:3;unsignedshorts3:3;unsignedshorts4:7;}*;第三大塊:函數(shù)通過函數(shù)修改變量的值具體面試題例如:如下,通過修改change函數(shù)的定義和調(diào)用,讓第4行執(zhí)行完,a的值編程13,p指向b。voidchange()//第5行,可以改{}voidmain(){inta=10;//第1行,不許改intb=11;//第2行,不許改int*p=&a;//第3行,不許改change();//第4行,可以改}【面試考察點】規(guī)則:如果通過函數(shù)修改一個變量的值,則需要傳給這個函數(shù)變量的地址。這里的陷阱是,既要改變變量的值,還要改變指針的值。80%的學(xué)員錯在:沒有成功修改指針的值。其實這很好理解,指針不也是一種變量嗎?.voidchange(int**pp,int*p_b)//第5行,可以改{**pp=13;*p=p_b;}voidmain(){inta=10;//第1行,不許改intb=11;//第2行,不許改int*p=&a;//第3行,不許改change(&p,&b);//第4行,可以改}【一句話擺平】通過函數(shù)改變變量的值,則需要傳遞變量的地址〔即一級指針〕;改變指針的值,則需要傳遞指針的地址〔即二級指針〕;改變二級指針的值,則需要傳遞二級指針的地址〔即三級指針〕;以此類推。這個題目是區(qū)分應(yīng)屆生和有編程經(jīng)歷人的標志。庫函數(shù)實現(xiàn)這里有三道題,我只重點分析第一道,其它兩題的代碼僅供參考(1).strcpy的函數(shù)原型:char*strcpy(char*strDest,constchar*strSrc)其中strDest是目的字符串,strSrc是源字符串。不調(diào)用C++/C的字符串庫函數(shù),請編寫函數(shù)strcpy?!军c評】此問題或類似問題被問到的頻率極高;首先要全部背上,一個字不能錯〔默寫幾遍〕;其次要徹底理解。答案:【注意點1】有的公司不提供函數(shù)聲明,這里面試官考察兩點:其一,是否有const,這涉及到參數(shù)的平安性,是否會有可能被函數(shù)修改〔原則上,不允許被函數(shù)修改的入?yún)?,都需要用const限定!〕;其二,入?yún)⒚欠褚?guī),首先從名字能看出誰是目的誰是源頭,其次是從名字能看出是指針。char*strcpy(char*p_dst,constchar*p_src){【注意點2】這是函數(shù)step1:變量定義和賦值。這個代碼塊的原則是:變量定義放在函數(shù)開場,且要初始化。在本函數(shù)中,先記錄下指針,用來返回用char*p_temp=p_dst;【注意點3】這是函數(shù)step2:入?yún)⒂行詸z查,沒有這一步的人直接被判死刑。這個代碼塊的原則是:所有有可能的風(fēng)險全部檢測一遍,能發(fā)現(xiàn)多少就多少在本函數(shù)中,本代碼塊須判斷是否為空和地址是否重疊。判斷為空時NULL放在等于號的前面,這是良好的工程習(xí)慣,常量在前。if(NULL==p_dst||NULL==p_src){returnNULL;}.if(p_dst==p_src){returnp_dst;}【注意點4】這是函數(shù)step3:業(yè)務(wù)功能代碼塊。這是函數(shù)的功能主體。這個代碼塊的原則是:用簡潔易懂的語言來實現(xiàn)業(yè)務(wù)功能,且無漏洞在本函數(shù)中,本代碼塊考察核心是:p_dst最后是否以‘\0’結(jié)尾。盡管代碼寫的沒有突出這一點,但應(yīng)聘時需要記住:所有字符串操作,都不要忘記結(jié)尾的‘\0’!很多學(xué)員面試卡在這個地方而不自知!while((*p_dst++=*p_src++)!=‘\0’);【注意點5】這是函數(shù)step4:結(jié)尾處理。這個代碼塊的原則是:函數(shù)功能已實現(xiàn)完畢,如何正確地收尾在本函數(shù)中,本代碼塊就一句話,返回正確的地址。returnp_temp;}(2).memcpy的函數(shù)原型:void*memcpy(void*dest,void*src,unsignedintcount);其中dest是目的地址,src是源地址,count是拷貝存長度。void*memcpy(void*dst,constvoid*src,unsignedintlen){registerchar*d;registerchar*s;if(len==0)returndst;if(is_overlap(dst,src,len,len))plain3("memcpy",dst,src,len);if(dst>src){d=(char*)dst+len-1;s=(char*)src+len-1;while(len>=4){*d--=*s--;*d--=*s--;*d--=*s--;*d--=*s--;len-=4;}while(len--){*d--=*s--;}}elseif(dst<src){d=(char*)dst;s=(char*)src;while(len>=4){*d++=*s++;*d++=*s++;.*d++=*s++;*d++=*s++;len-=4;}while(len--){*d++=*s++;}}returndst;}(3).a(chǎn)toi的函數(shù)原型:intatoi(constchar*string);其中string是數(shù)字字符串。intatoi(charconst*string){intvalue;value=0;while(*string>='0'&&*string<='9'){value*=10;value+=*string-'0';++string;}if(*string!='0')value=0;returnvalue;}第四大塊:指針&存指針的身份要明確,這是前提用變量a給出下面的定義:a)一個整型數(shù)〔Aninteger〕b)一個指向整型數(shù)的指針〔Apointertoaninteger〕c)一個指向指針的的指針,它指向的指針是指向一個整型數(shù)〔Apointertoapointertoaninteger〕d)一個有10個整型數(shù)的數(shù)組〔Anarrayof10integers〕e)一個有10個指針的數(shù)組,該指針是指向一個整型數(shù)的〔Anarrayof10pointerstointegers〕f)一個指向有10個整型數(shù)數(shù)組的指針〔Apointertoanarrayof10integers〕g)一個指向函數(shù)的指針,該函數(shù)有一個整型參數(shù)并返回一個整型數(shù)〔Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger〕h)一個有10個指針的數(shù)組,該指針指向一個函數(shù),該函數(shù)有一個整型參數(shù)并返回一個整型數(shù)〔Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger〕答案是:a)inta;//Anintegerint*a;//Apointertoanintegerint**a;//Apointertoapointertoanintegerinta[10];//Anarrayof10integersint*a[10];//Anarrayof10pointerstointegersint(*a)[10];//A(*a)(int);//Apointertoafunctionathattakesanintegerargumentandreturnsanintegerint(*a[10])(int);//Anarrayof10pointerstofunctionsthattakeanintegerargumentandreturnaninteger人們經(jīng)常聲稱這里有幾個問題是那種要翻一下書才能答復(fù)的問題,我同意這種說法。當我寫這篇文章時,為了確定語法的正確性,我確實查了一下書。但是當我被面試的時候,我期望被問到這個問題〔或者相近的問題〕。因為在被面試的這段時間里,我確定我知道這個問題的答案。應(yīng)試者如果不知道所有的答案〔或至少大局部答案〕,則也就沒有為這次面試做準備,如果該面試者沒有為這次面試做準備,則他又能為什么出準備呢?【面試點評】在嚴格的面試官面前,僅僅知道這些“是什么〞還遠遠不夠,因為簡單的記憶大局部人都能答出來,還停留在“變量〞那個層次,還不是指針??赡苓€會追問如下問題〔以函數(shù)指針為例〕:追問1:如何對它們進展賦值?intfunc(int);int(*p_func)(int);p_func=func;//分析:函數(shù)名本身是個地址;指針也是個地址,因此可以賦值。有人寫作p_func=&func,別這么寫。因為你去面試是為了證明你這個知識點我懂、能編程干活即可,而不是記憶很多自己不好理解的、真正面試時自己容易全混淆了的東東。追問2:如何通過它來調(diào)用函數(shù)?p_func(10);//分析:既然p_func就是func賦值來的,當然可以替代。有人寫作*p_func〔10〕,同理,別這么寫?!竞瘮?shù)指針分析】一個面試題是:隨便寫一個函數(shù),然后在寫一個函數(shù)指針指向它。題:為如下的函數(shù)寫出相應(yīng)的指針1)voidfunA();2)int*funB(inttemp);3)constint*funC(int*p_temp,int(*p)())答案:4)void(*p_funA)();5)int*(*p_funB)(inttemp);6)constint*〔*p_funC〕(int*p_temp,int(*p)())有沒有發(fā)現(xiàn)規(guī)律?C語言是一個構(gòu)造性語言,等級森嚴;同時也是一個形而上的語言,套用構(gòu)造即可。如果你還沒有比照發(fā)現(xiàn)出規(guī)律,那說明你沒有在認真準備面試,而是在急躁地背題目,真正面試時機來了你也很可能把握不住。規(guī)律就是,把“函數(shù)名〞換成“*p〞即可,其它的任何地方都不要動。【構(gòu)造分析】首先找到變量或函數(shù)名,分別是funA,funB,funC;然后看這些變量名先和誰結(jié)合?規(guī)則:同一優(yōu)先級下,右結(jié)合原則。2〕中的funB先和“()〞結(jié)合,所以身份明確,是個函數(shù)〔帶括號的一定和函數(shù)有關(guān)〕;則,是個什么樣的函數(shù)呢?“int*〞說明,這是一個返回int型指針的函數(shù);.5〕中的p_funB,因為括號的關(guān)系,先和前面的“*〞結(jié)合,所以身份明確,是個指針;則,是個什么樣的指針呢?后面的括號說明,這是一個指向函數(shù)的指針;則,指向什么樣的函數(shù)呢?“int*〞說明,這個函數(shù)返回int型指針。上門的h)同樣分析:帶〞[]〞一定和數(shù)組有關(guān)系,大家做類型的推演,然后寫代碼在機器上跑一下“定義、賦值、調(diào)用〞三步驟。什么是回調(diào)函數(shù)。如何使用,使用的特點。數(shù)組和指針inta[5]={1,2,3,4,5};int*p1=(int*)(&a6+1);int*p2=(int*)(a+1);printf(“%d〞,*(p1-1));printf(“%d〞,*(p2-1));程序運行結(jié)果?a是數(shù)組首元素的首地址,其類型為int[5],&a為數(shù)組的首地址,類型為int〔*〕[5]。a的值==&a的值,他們都表示一個地址。但是請注意區(qū)分他們的類型。&a+1,向后偏了sizeof(a)則多bytes而a+1,指向后廉價了sizeof(int)bytes存空間計算:(1)、charstr[]=“Hello〞;char*p=str;intn=10;//請計算sizeof(str)=6sizeof(p)=4sizeof(n)=4strlen(str)=5strlen(p)=5(2)、voidFunc(charstr[100]){//請計算sizeof(str)= 4}(3)、void*p=malloc(100);//請計算sizeof(p)=4幾道經(jīng)典面試題,用了十幾年了:(1)、voidGetMemory(char*p){p=(char*)malloc(100);}.voidTest(void){char*str=NULL;GetMemory(str);strcpy(str,"helloworld");printf(str);}請問運行Test函數(shù)會有什么樣的結(jié)果?答:程序崩潰。因為GetMemory并不能傳遞動態(tài)存,Test函數(shù)中的str一直都是NULL。strcpy(str,"helloworld");將使程序崩潰。(2)、voidGetMemory(char**p,intnum){*p=(char*)malloc(num);}voidTest(void){char*str=NULL;GetMemory(&str,100);strcpy(str,"hello");printf(str);}請問運行Test函數(shù)會有什么樣的結(jié)果?答:〔1〕能夠輸出hello〔2〕存泄漏(3)、char*GetMemory(void){charp[]="helloworld";returnp;}voidTest(void){char*str=NULL;str=GetMemory();printf(str);}請問運行Test函數(shù)會有什么樣的結(jié)果?答:可能是亂碼。因為GetMemory返回的是指向“棧存〞的指針,該指針的地址不是NULL,但其原現(xiàn)的容已經(jīng)被去除,新容不可知。.(4)、voidTest(void){char*str=(char*)malloc(100);strcpy(str,“hello〞);free(str);if(str!=NULL){strcpy(str,“world〞);printf(str);}}請問運行Test函數(shù)會有什么樣的結(jié)果?答:篡改動態(tài)存區(qū)的容,后果難以預(yù)料,非常危險。因為free(str);之后,str成為野指針,if(str!=NULL)語句不起作用。認識什么是字符串嗎?這道題沒有一眼看出來,說明這一塊你很危險intmian(){charstr[10];charstr2[10];inti;for(i=0;i<10;i++){str[i]=‘a(chǎn)’+i;}strcpy(str2,str);}請問運行程序會有什么樣的結(jié)果?指針和地址,你理解嗎?嵌入式系統(tǒng)經(jīng)常具有要求程序員去訪問*特定的存位置的特點。在*工程中,要求設(shè)置一絕對地址為0*67a9的整型變量的值為0*aa66。編譯器是一個純粹的ANSI編譯器。寫代碼去完成這一任務(wù)。這一問題測試你是否知道為了訪問一絕對地址把一個整型數(shù)強制轉(zhuǎn)換〔typecast〕為一指針是合法的。這一問題的實現(xiàn)方式隨著個人風(fēng)格不同而不同。典型的類似代碼如下:int*ptr;ptr=(int*)0*67a9;*ptr=0*aa55;一個較晦澀的方法是:*(int*const)(0*67a9)=0*aa55;即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。盡管不像非嵌入式計算機則常見,嵌入式系統(tǒng)還是有從堆〔heap〕中動態(tài)分配存的過程的。則嵌入式系統(tǒng)中,動態(tài)分配存可能發(fā)生的問題是什么?這里,我期望應(yīng)試者能提到存碎片,碎片收集的問題,變量的持行時間等等。這個主題已經(jīng).在ESP雜志中被廣泛地討論過了〔主要是P.J.Plauger,他的解釋遠遠超過我這里能提到的任何解釋〕,所有回過頭看一下這些雜志吧!讓應(yīng)試者進入一種虛假的平安感覺后,我拿出這么一個小節(jié)目:下面的代碼片段的輸出是什么,為什么?char*ptr;if((ptr=(char*)malloc(0))==NULL)puts("Gotanullpointer");elseputs("Gotavalidpointer");這是一個有趣的問題。最近在我的一個同事不經(jīng)意把0值傳給了函數(shù)malloc,得到了一個合法的指針之后,我才想到這個問題。這就是上面的代碼,該代碼的輸出是“Gotavalidpointer〞。我用這個來開場討論這樣的一問題,看看被面試者是否想到庫例程這樣做是正確。得到正確的答案固然重要,但解決問題的方法和你做決定的根本原理更重要些。第五大塊:鏈表設(shè)計一個用鏈表表示的直接插入排序算法typedefstructnode{intkey;structnode*ne*t;}NODE;sort(NODE*h){NODE*p,*h1,*t,*q;h1=h->ne*t->ne*t;h->ne*t->ne*t=null;while(h1!=null){t=h1;h1=h1->ne*t;q=h;p=h->ne*t;while(p->num>t->num&&p!=null){q=p;p=p->ne*t;}t->ne*t=p;q->ne*t=t;}}鏈表題:一個鏈表的結(jié)點構(gòu)造structNode{intdata;Node*ne*t;};typedefstructNodeNode;(1)鏈表的頭結(jié)點head,寫一個函數(shù)把這個鏈表逆序(Intel)Node*ReverseList(Node*head)//鏈表逆序.{if(head==NULL||head->ne*t==NULL)returnhead;Node*p1=head;Node*p2=p1->ne*t;Node*p3=p2->ne*t;p1->ne*t=NULL;while(p3!=NULL){p2->ne*t=p1;p1=p2;p2=p3;p3=p3->ne*t;}p2->ne*t=p1;head=p2;returnhead;}(2)兩個鏈表head1和head2各自有序,請把它們合并成一個鏈表依然有序。(保存所有結(jié)點,即便大小一樣〕Node*Merge(Node*head1,Node*head2){if(head1==NULL)returnhead2;if(head2==NULL)returnhead1;Node*head=NULL;Node*p1=NULL;Node*p2=NULL;if(head1->data<head2->data){head=head1;p1=head1->ne*t;p2=head2;}else{head=head2;p2=head2->ne*t;p1=head1;}Node*pcurrent=head;while(p1!=NULL&&p2!=NULL){.if(p1->data<=p2->data){pcurrent->ne*t=p1;pcurrent=p1;p1=p1->ne*t;}else{pcurrent->ne*t=p2;pcurrent=p2;p2=p2->ne*t;}}if(p1!=NULL)pcurrent->ne*t=p1;if(p2!=NULL)pcurrent->ne*t=p2;returnhead;}(3)兩個鏈表head1和head2各自有序,請把它們合并成一個鏈表依然有序,這次要求用遞歸方法進展。(Autodesk)答案:Node*MergeRecursive(Node*head1,Node*head2){if(head1==NULL)returnhead2;if(head2==NULL)returnhead1;Node*head=NULL;if(head1->data<head2->data){head=head1;head->ne*t=MergeRecursive(head1->ne*t,head2);}else{head=head2;head->ne*t=MergeRecursive(head1,head2->ne*t);}returnhead;}(4)單鏈表刪除:假設(shè)表中有數(shù)據(jù)281169,題目是:找到數(shù)據(jù)為11的節(jié)點并將之從鏈表中刪除;【題目誤區(qū)】這里要注意,只能用一次循環(huán)!如果用了兩次,那就被面試官判為錯誤.如何判斷一個單鏈表是有環(huán)的?〔注意不能用標志位,最多只能用兩個額外指針〕structnode{charval;node*ne*t;}boolcheck(constnode*head){}//returnfalse:無環(huán);true:有環(huán)一種O〔n〕的方法就是〔搞兩個指針,一個每次遞增一步,一個每次遞增兩步,如果有環(huán)的話兩者必然重合,反之亦然〕:boolcheck(constnode*head){if(head==NULL)returnfalse;node*low=head,*fast=head->ne*t;while(fast!=NULL&&fast->ne*t!=NULL){low=low->ne*t;fast=fast->ne*t->ne*t;if(low==fast)returntrue;}returnfalse;}雙向鏈表的刪除結(jié)點第六大塊:算法寫在具體之前:我們一個學(xué)員去面試,面試官問:你的工程中用到算法了嗎?他想了想說,沒有。結(jié)果可想而知。后來我問他,你“***管理系統(tǒng)中“,沒有排序嗎?他說有啊,我說那里面沒有用到算法嗎?他說,冒泡是算法嗎?無語?。?!【一句話擺平】所有排序、查找,必然用到算法查找算法#include<stdio.h>#include<stdlib.h>intMA*=100000;/*二分查找*/intbs(intdata[],intdvalue){intl,u,m;intp;l=0;u=MA*;for(;;){if(l>u)return-1;m=(l+u)/2;if(data[m]==dvalue){returnm;}elseif(data[m]>dvalue){u=m-1;}else{.l=m+1;}}}/*順序查找*/intss(intdata[],intdvalue){inti;intl=len(data);for(i=0;i<MA*;i++){printf("%d\n",data[i]);if(data[i]==dvalue){returni;}}return-1;}intmain(){//intMA*=1000;intdata[MA*];inti;//給數(shù)組賦值for(i=0;i<MA*;i++){data[i]=i*10;}//要查找的值intvalue=300;//順序查找ints=ss(data,value);printf("%d\n",s);//二分查找intd=bs(data,value);printf("%d\n",d);return0;}快速排序編寫算法判斷二叉樹是否是完全二叉樹〔此題看情況〕分析:完全二叉樹是指在一棵二叉樹中除最后一層外,其余層都是滿的,并且最后一層或者是滿的,或者在右邊缺少連續(xù)假設(shè)干結(jié)點。要判定一棵二叉樹是否完全二叉樹,應(yīng)先建立一棵二叉樹,此例采用鏈式存儲構(gòu)造的先序算法建立一棵二叉樹。判定一棵二叉樹是否是完全二叉樹,可以使用隊列,在層次遍歷的過程中利用完全二叉樹“假設(shè)*結(jié)點無左孩子,就一定沒有右孩子〞的原則進展判斷。答案:#include<stdio.h>typedefcharElementType;.typedefstructnode{ElementTypedata;structnode*LChild,*RChild;}BinNode,*BinTree;voidCreateBinTree(BinTree*root){charch;ch=getchar();if(ch==’#’)*root=NULL;else{*root=(BinTree)malloc(sizeof(BinNode));(*root)->data=ch;CreateBinTree(&((*root)->LChild));CreateBinTree(&((*root)->RChild));}}intJudgeplete(BinTreebt)/*判斷二叉樹是否是完全二叉樹,是返回1,不是返回0*/{inttag=0,front,rear;BinTreep=bt,Q[50]; /*Q是隊列,元素是二叉樹結(jié)點指針,容量足夠大*/if(p==NULL)return1;front=rear=0;Q[++rear]=p; /*初始化隊伍,根結(jié)點指針入隊*/while(front!=rear){p=Q[++front];if(p->LChild&&!tag)Q[++rear]=p->LChild;/*左孩子入隊*/elseif(p->LChild)return0; /*前邊已有結(jié)點為空,本結(jié)點不空*/elsetag=1; /*首次出現(xiàn)構(gòu)造為空*/if(p->RChild&&!tag)Q[++rear]=p->RChild;/*右孩子入隊*/elseif(p->RChild)return0;elsetag=1;}return1;}main(){inty;BinTreebt;printf("請輸入結(jié)點數(shù)據(jù):");.CreateBinTree(&bt);y=Judgeplete(bt);if(y==1)printf("該二叉樹是完全二叉樹\n");elseprintf("該二叉樹不是完全二叉樹\n");}數(shù)據(jù)序列為〔12,5,9,20,6,31,24〕,對該數(shù)據(jù)序列進展排序,試寫出插入排序和冒泡排序unsignedintintvert(unsignedint*,intp,intn)實現(xiàn)對*的進展轉(zhuǎn)換,p為起始轉(zhuǎn)化位,n為需要轉(zhuǎn)換的長度,假設(shè)起始點在右邊.如*=0b00010001,p=4,n=3轉(zhuǎn)換后*=0b01100001unsignedintintvert(unsignedint*,intp,intn){unsignedint_t=0;unsignedint_a=1;for(inti=0;i<n;++i){_t|=_a;_a=_a<<1;}_t=_t<<p;*^=_t;return*;}單詞反轉(zhuǎn)如:thisisapig反轉(zhuǎn)后:pigaisthis寫一個函數(shù)實現(xiàn)該反轉(zhuǎn)?!军c評】要求不能增加復(fù)雜度寫一個程序,判斷運行程序的系統(tǒng)的是大字節(jié)序還是小字節(jié)序?寫函數(shù)實現(xiàn)大小字節(jié)序轉(zhuǎn)換。voidcheckSystem(){unioncheck{inti;charch;}c;c.i=1;if((char)1==c.ch)printf("系統(tǒng)是小字節(jié)序\n");elseprintf("系統(tǒng)是大字節(jié)序\n");}intmain(){.checkSystem();}用C語言完成以下這個子程序,要求:1,定義一個一維數(shù)組,數(shù)組大小為24。2,產(chǎn)生0-23的隨機數(shù)。3,將產(chǎn)生的隨機數(shù)存入數(shù)組,要求數(shù)組中的每個數(shù)據(jù)不能一樣。4,補充說明:這個子程序要求每次調(diào)用后,這個數(shù)組里面就存放了0-23這些數(shù)據(jù),而且這些數(shù)據(jù)沒有重復(fù)的。5,注意,C語言有隨機數(shù)函數(shù),可以用函數(shù)產(chǎn)生隨機數(shù)。RAND〔N〕voidRandArrayN(int*a,intn){inti,t,;n=n-1;for(i=0;i<=n;i++)a[i]=0;//全部清零,還沒有置數(shù)的狀態(tài)。for(i=0;i<n;i++){ //只循環(huán)了n-1次,每次置入的數(shù)據(jù)分別為n-1,n-2,...,1,最后剩余未置(非零)數(shù)的那個位置就本身已經(jīng)置入0了。while(a[t=rand(n)]!=0);//每次找一個未置數(shù)位置//假設(shè)該位置已經(jīng)放下一個數(shù)(不等于0),則找下一個位置,直到找到為0的位置(還沒有置入一個數(shù))a[t]=n-i;//第i次找到的位置置入數(shù)n-i,}}voidmain(){inta[N];RandArrayN(a,N);}intmain(){intt,i;inta[24];memset(a,0,sizeof(a));srand((int)time(0));for(i=0;i<=22;i++){while(a[t=rand()%23]!=0);a[t]=23-i;}for(i=0;i<24;i++){printf("%d",a[i]);}}有一個數(shù)組a[1000]存放0--1000;要求每隔二個數(shù)刪掉一個數(shù),到末尾時循環(huán)至開頭繼續(xù)進展,求最后一個被刪掉的數(shù)的原始下標位置。.以7個數(shù)為例:{0,1,2,3,4,5,6,7}0-->1-->2(刪除)-->3-->4-->5(刪除)-->6-->7-->0(刪除),如此循環(huán)直到最后一個數(shù)被刪除。方法1:數(shù)組#includeusingnamespacestd;#definenull1000intmain(){intarr[1000];for(inti=0;i<1000;++i)arr[i]=i;intj=0;intcount=0;while(coun

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論