欧美1区2区3区激情无套,两个女人互添下身视频在线观看,久久av无码精品人妻系列,久久精品噜噜噜成人,末发育娇小性色xxxx

【秋招】嵌入式面試八股文-C語言 內存/預處理/其他

1 內存

1.1 C語言中內存分配的方式有幾種?

(1)靜態(tài)存儲區(qū)分配

  • 內存分配在程序編譯之前完成,且在程序的整個運行期間都存在,例如全局變量、靜態(tài)變量等

(2)棧上分配

  • 在函數(shù)執(zhí)行時,函數(shù)內的局部變量的存儲單元在棧上創(chuàng)建,函數(shù)執(zhí)行結束時這些存儲單元自動釋放局部變量、函數(shù)內參數(shù)都在棧上

(3)堆上分配 ?

  • New開辟的空間在堆上

1.2 堆與棧有什么區(qū)別?

(1)申請方式

  • 棧的空間由操作系統(tǒng)自動分配/釋放,堆上的空間手動分配/釋放

(2)申請大小的限制??臻g有限

  • 在Windows下,棧是向低地址擴展的數(shù)據(jù)結構,是一塊連續(xù)的內存的區(qū)域這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的,在WINDOWS下,棧的大小是2M(也有的說是1M,總之是 一個編譯時就確定的常數(shù)),如果申請的空間超過棧的剩余空間時,將提示overflow因此,能從棧獲得的空間較小堆是很大的自由存儲區(qū)堆是向高地址擴展的數(shù)據(jù)結構,是不連續(xù)的內存區(qū)域這是由于系統(tǒng)是用 鏈表來存儲的空閑內存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址堆的大小受限于計算機系統(tǒng)中有效的虛擬內存由此可見,堆獲得的空間比較靈活,也比較大

(3)申請效率

  • 棧由系統(tǒng)自動分配,速度較快但程序員是無法控制的
  • 堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便

1.3 棧在C語言中有什么作用?

  • C語言中棧用來存儲臨時變量,臨時變量包括函數(shù)參數(shù)和函數(shù)內部定義的臨時變量函數(shù)調用中和函數(shù)調用相關的函數(shù)返回地址,函數(shù)中的臨時變量,寄存器等均保存在棧中,函數(shù)調動返回后從棧中恢復寄存器和臨時變量等函數(shù)運行場景
  • 多線程編程的基礎是棧,棧是多線程編程的基石,每一個線程都最少有一個自己專屬的棧,用來存儲本線程運行時各個函數(shù)的臨時變量和維系函數(shù)調用和函數(shù)返回時的函數(shù)調用關系和函數(shù)運行場景。操作系統(tǒng)最基本的功能是支持多線程編程,支持中斷和異常處理,每個線程都有專屬的棧,中斷和異常處理也具有專屬的棧,棧是操作系統(tǒng)多線程管理的基石

1.4 C語言函數(shù)參數(shù)壓棧順序是怎樣的?

  • 先理解入棧和出棧:

  • 棧的范圍是由 ss * 10H ?至 ss * 10H + sp
  • (ss)指堆棧寄存器:存放堆棧段起始地址的高16位(即16進制下五個數(shù)的前四個數(shù))
  • (sp)指堆棧指針:用于存放棧頂?shù)倪壿嬈频刂?/span>
  • 棧的棧底指針不變,棧頂?shù)闹羔橂Ssp的改變而改變由于棧的棧底地址是高地址,棧頂?shù)刂肥堑偷刂匪援敆4嫒霐?shù)據(jù)時,會先將sp減去存入數(shù)據(jù)的字節(jié)數(shù),然后再將數(shù)據(jù)存入反之,當棧取出數(shù)據(jù)時,會將數(shù)據(jù)取出后將sp加上取出數(shù)據(jù)的字節(jié)數(shù)(例如,當sp=0800H,ss=2360H時,若此時加入20個字節(jié)的數(shù)據(jù),那么就要將sp-20,此時的棧頂就是ss * 10H + sp)
  • 注:所謂高地址與低地址,前面的地址稱為低地址,后面的地址稱為高地址,例如23600H與23E00H,此時23600H為低地址,23E00H為高地址
  • 回答這個問題:從右至左
  • C語言參數(shù)入棧順序的好處就是可以動態(tài)變化參數(shù)個數(shù)自左向右的入棧方式,最前面的參數(shù)被壓在棧底除非知道參數(shù)個數(shù),否則是無法通過棧指針的相對位移求得最左邊的參數(shù)這樣就變成了左邊參數(shù)的個數(shù)不確定,正好和動態(tài)參數(shù)個數(shù)的方向相反因此,C語言函數(shù)參數(shù)采用自右向左的入棧順序,主要原因是為了支持可變長參數(shù)形式

例如:printf(const char* format,…)

  • printf函數(shù)是一個不定參函數(shù)
  • 編譯器通過format的%占位符的個數(shù)來獲取參數(shù)的個數(shù)
  • 假設函數(shù)壓棧順序是從左至右,format先入棧,各個參數(shù)再入棧,最后pc入棧入棧完之后,想知道參數(shù)的個數(shù)就要讀取format,但要讀取format就得知道參數(shù)的個數(shù),陷入了一個死循環(huán)
  • 但是,如果函數(shù)壓棧順序是從右至左,未知個數(shù)的參數(shù)先入棧,format再入棧,最后壓pc入棧這時候要想知道參數(shù)的個數(shù)只需要將棧頂指針加2即可讀取到format?

1.5 C++的內存管理是怎樣的?

在C++中,虛擬內存分為代碼段、數(shù)據(jù)段、BSS段、堆區(qū)、文件映射區(qū)以及棧區(qū)六部分

  • 代碼段:包括只讀存儲區(qū)和文本區(qū),其中只讀存儲區(qū)存儲字符串常量,文本區(qū)存儲程序的機器代碼
  • 數(shù)據(jù)段:存儲程序中已初始化的全局變量和靜態(tài)變量
  • BSS段:存儲未初始化的全局變量和靜態(tài)變量(局部+全局),以及所有被初始化為0的全局變量和靜態(tài)變量
  • 堆區(qū):調用new/malloc函數(shù)時在堆區(qū)動態(tài)分配內存,同時需要調用delete/free來手動釋放申請的內存
  • 映射區(qū):存儲動態(tài)鏈接庫以及調用mmap函數(shù)進行的文件映射
  • 棧:使用??臻g存儲函數(shù)的返回地址、參數(shù)、局部變量、返回值

1.6 什么是內存泄漏?

  • 簡單地說就是申請了一塊內存空間,使用完畢后沒有釋放掉
  • 它的一般表現(xiàn)方式是程序運行時間越長,占用內存越多,最終用盡全部內存,整個系統(tǒng)崩潰由程序申請的一塊內存,且沒有任何一個指針指向它,那么這塊內存就泄露了

1.7 如何判斷內存泄漏?

  • 良好的編碼習慣,盡量在涉及內存的程序段,檢測出內存泄露當程式穩(wěn)定之后,在來檢測內存泄露時,無疑增加了排除的困難和復雜度使用了內存分配的函數(shù),一旦使用完畢,要記得要使用其相應的函數(shù)釋放掉
  • 將分配的內存的指針以鏈表的形式自行管理,使用完畢之后從鏈表中刪除,程序結束時可檢查改鏈表
  • Boost 中的smart pointer
  • 一些常見的工具插件,如ccmalloc、Dmalloc、Leaky等等

1.8?new/delete與malloc/free的區(qū)別是什么?

  • 在C++中,申請動態(tài)內存和釋放動態(tài)內存,用new/delete 和 malloc/free都可以,new和malloc動態(tài)申請的內存都位于堆中,無法被操作系統(tǒng)回收,需要對應的delete/free來釋放空間

void *malloc(int size);

  • 說明:malloc向系統(tǒng)申請分配指定size個字節(jié)的內存空間返回類型是 void* 類型void* 表示未確定類型的指針C,C++規(guī)定,void* 類型可以強制轉換為任何其它類型的指針
  • 對于類的對象而言,malloc/free無法滿足動態(tài)對象的要求,對象在創(chuàng)建時要自動執(zhí)行構造函數(shù),在對象消亡之前要自動執(zhí)行析構函數(shù),而malloc/free 不在編譯器控制權限之內,無法執(zhí)行構造函數(shù)和析構函數(shù)
  • 當然對于沒有資源要清理的類,不調用析構函數(shù)也沒有太大的問題,即使用free或delete沒有區(qū)別但萬一有一些類的成員是指針,而這個指針又在堆上開辟了空間,這時不調用析構函數(shù)去釋放這個指針指向的這段空間,就會造成內存泄漏delete會調用析構函數(shù),釋放指針成員變量的空間,再銷毀對象本身的空間;而free只釋放了對象本身的空間,而指針成員所指向的空間沒有被釋放

具體而言:

  • new 能夠自動計算需要分配的內存空間,而malloc需要手工計算字節(jié)數(shù)
  • new與delete帶具體類型的指針,malloc與free返回void類型的指針
  • new 將調用構造函數(shù),而malloc不能;delete將調用析構函數(shù),而free不能
  • malloc/free 需要庫文件<stdlib.h>支持,而new/delete不需要庫文件支持
  • new操作可以重載,可以自定義內存分配策略,不做內存分配,或者分配到非內存設備上而malloc不能

delete和free被調用后,內存不會不會立即收回,指針也不會指向空,delete或free僅僅是告訴操作系統(tǒng),這一塊內存被釋放啦,還可以做其他用途由于沒有對這塊內存進行寫操作,所以內存中的變量數(shù)值并沒有發(fā)生變化,出現(xiàn)野指針的情況,因此,釋放完內存后需要將指針向量置為空

2 預處理

2.1 預處理器標識#error的目的是什么?

  • #error預處理指令的作用是,編譯程序時,只要遇到#error就會生成一個編譯錯誤提示消息,并停止編譯其語法格式為:#error error-message
  • 下面舉個例子: 程序中往往有很多的預處理指令

  • 當程序比較大時,往往有些宏定義是在外部指定的(如makefile),或是在系統(tǒng)頭文件中指定的,當你 不太確定當前是否定義了 XXX 時,就可以改成如下這樣進行編譯:

  • 這樣,如果編譯時出現(xiàn)錯誤,輸出了XXX has been defined,表明宏XXX已經(jīng)被定義了

2.2 如何使用 define聲明個常數(shù),用以表明1年中有多少秒(忽略閏年問題)

  • 考慮到可能存在數(shù)據(jù)溢出問題,更加規(guī)范化的寫法是使用長整型類型,即UL類型,告訴編譯器這個常數(shù)是長整型數(shù)

2.3 # include< filename. h>和#include" filename. h"有什么區(qū)別?

  • 對于 include< filename. h>,編譯器先從標準庫路徑開始搜索filename.h,使得系統(tǒng)文件調用較快
  • 對于# include“ filename.h”,編譯器先從用戶的工作路徑開始搜索filename.h,然后去尋找系統(tǒng)路徑,使得自定義文件較快

2.4?頭文件的作用有哪些?

  • 頭文件的作用主要表現(xiàn)為以下兩個方面:
  • 通過頭文件來調用庫功能出于對源代碼保密的考慮,源代碼不便(或不準)向用戶公布,只要向用戶提供頭文件和二進制的庫即可用戶只需要按照頭文件中的接口聲明來調用庫功能,而不必關心接口是怎么實現(xiàn)的編譯器會從庫中提取相應的代碼
  • 頭文件能加強類型安全檢查當某個接口被實現(xiàn)或被使用時,其方式與頭文件中的聲明不一致,編譯器就會指出錯誤,大大減輕程序員調試、改錯的負擔

2.5 在頭文件中定義靜態(tài)變量是否可行,為什么?

  • 不可行,如果在頭文件中定義靜態(tài)變量,會造成資源浪費的問題,同時也可能引起程序錯誤因為如果在使用了該頭文件的每個C語言文件中定義靜態(tài)變量,按照編譯的步驟,在每個頭文件中都會單獨存在一個靜態(tài)變量,從而會引起空間浪費或者程序錯誤所以,不推薦在頭文件中定義任何變量,當然也包括靜態(tài)變量

2.6 寫一個"標準"宏MIN ,這個宏輸入兩個參數(shù)并返回較小的一個

3 其他C語言面試問題

3.1 C語言宏中“#”和“##”的用法

(1)“#”字符串化操作符

  • 作用:#可以把一個宏參數(shù)直接轉換成相應的字符串比如有下面這個宏:

則進行如下調用:

  • 最后其執(zhí)行效果如下面程序一樣:

  • 也就是說,最后輸出的是宏參數(shù)的參數(shù)名即:將宏參數(shù)直接轉換成相應得字符串

(2)“##”符號連接操作符

作用:將宏定義的多個形參轉換成一個實際參數(shù)名

則下面第一個圖的代碼和第二個圖的代碼等價(圖片點開觀看會很清晰)

3.2 extern”C” 的作用是什么?

  • extern "C"的主要作用就是為了能夠正確實現(xiàn)C++代碼調用其他C語言代碼加上extern "C"后,會指示編譯器這部分代碼按C語言的進行編譯,而不是C++的

3.3 strlen("\0") =? sizeof("\0")=? 兩者結果與區(qū)別

  • strlen("\0") =0,sizeof("\0")=2
  • strlen用來計算字符串的長度(在C/C++中,字符串是以"\0"作為結束符的),它從內存的某個位置(可以是字符串開頭,中間某個位置,甚至是某個不確定的內存區(qū)域)開始掃描直到碰到第一個字符串結束符\0為止,然后返回計數(shù)器值sizeof是C語言的關鍵字,它以字節(jié)的形式給出了其操作數(shù)的存儲大小,操作數(shù)可以是一個表達式或括在括號內的類型名,操作數(shù)的存儲大小由操作數(shù)的類型決定

3.4 C語言中 struct與 union的區(qū)別是什么?

  • struct(結構體)與 union(聯(lián)合體)是C語言中兩種不同的數(shù)據(jù)結構,兩者都是常見的復合結構,區(qū)別主要表現(xiàn)在以下兩個方面:
  • 結構體與聯(lián)合體雖然都是由多個不同的數(shù)據(jù)類型成員組成的,但不同之處在于聯(lián)合體中所有成員共用一塊地址空間,即聯(lián)合體只存放了一個被選中的成員,而結構體中所有成員占用空間是累加的, 其所有成員都存在,不同成員會存放在不同的地址在計算一個結構型變量的總長度時,其內存空間大小等于所有成員長度之和(需要考慮字節(jié)對齊),而在聯(lián)合體中,所有成員不能同時占用內存空間,它們不能同時存在,所以一個聯(lián)合型變量的長度等于其最長的成員的長度
  • 對于聯(lián)合體的不同成員賦值,將會對它的其他成員重寫,原來成員的值就不存在了,而對結構體的不同成員賦值是互不影響的(圖片點開觀看會很清晰)

  • 假設為32位機器,int型占4個字節(jié), double型占8個字節(jié),char型占1個字節(jié),而DATE是一個聯(lián)合型變 量,聯(lián)合型變量共用空間,uion里面最大的變量類型是int[5],所以占用20個字節(jié),它的大小是20,而 由于 union中,double占了8個字節(jié),因此 union是要8個字節(jié)對齊,所占內存空間為8的倍數(shù)為了實現(xiàn) 8個字節(jié)對齊,所占空間為24.而data是一個結構體變量,每個變量分開占用空間,依次為
  • sizeof(int) + sizeof(DATE)+ sizeof( double)=4+24+8=36按照8字節(jié)對齊,占用空間為40,所以結果為 40+24=64

3.5?左值和右值是什么?

  • 左值是指可以出現(xiàn)在等號左邊的變量或表達式,它最重要的特點就是可寫(可尋址)也就是說,它的值可以被修改,如果一個變量或表達式的值不能被修改,那么它就不能作為左值
  • 右值是指只可以出現(xiàn)在等號右邊的變量或表達式它最重要的特點是可讀一般的使用場景都是把一個右值賦值給一個左值通常,左值可以作為右值,但是右值不一定是左值

3.6 有符號數(shù)和無符號數(shù)的運算?? ?

  • int a = -20, unsigned int b = 6,a+b是否大于6?
  • 有符號和無符號運算,強制轉換為無符號,所有a+b會變成(unsigned int)a+b;
  • (unsigned int)a 就會相當于無符號最大值-20,那么是一個非常大的值,這個值加上6,那么肯定是大于6的;
  • 最后的值是2^32-20+6=4294967282,肯定大于6

3.7 什么是短路求值?

  • 輸出結果為1輸出為什么不是2,而是1呢?
  • 其實,這里就涉及一個短路計算的問題由于i語句是個條件判斷語句,里 面是有兩個簡單語句進行或運算組合的復合語句,因為或運算中,只要參與或運算的兩個表達式的值都為真,則整個運算結果為真,而由于變量i的值為6,已經(jīng)大于0了,而該語句已經(jīng)為true,則不需要執(zhí)行后續(xù)的j+操作來判斷真假,所以后續(xù)的j++操作不需要執(zhí)行,j的值仍然為1
  • 因為短路計算的問題,對于&&操作,由于在兩個表達式的返回值中,如果有一個為假則整個表達式的值 都為假,如果前一個語句的返回值為 false,則無論后一個語句的返回值是真是假,整個條件判斷都為 假,不用執(zhí)行后一個語句,而a>b的返回值為 false,程序不執(zhí)行表達式n=c>d,所以,n的值保持為初值2

3.8 什么是大端和小端?

??大端:高地址存低字節(jié),低地址存高字節(jié)

??小端:低地址存低字節(jié),高地址存高字節(jié)

3.9 ++a和a++有什么區(qū)別?兩者是如何實現(xiàn)的?

??a++的具體運算過程為: 先用a,再執(zhí)行++

++a的具體運算過程為: ?先執(zhí)行++,再用a

?

#嵌入式筆面經(jīng)分享##秋招##嵌入式#

雙非本,211碩。本碩均為機械工程,自學嵌入式,在校招過程中拿到小米、格力、美的、比亞迪、海信、???、大華、江波龍等offer。八股文本質是需要大家理解,因此里面的內容一定要詳細、深刻!這個專欄是我個人的學習筆記總結,是對很多面試問題進行的知識點分析,專欄保證高質量,讓大家可以高效率理解與吸收里面的知識點!掌握這里面的知識,面試絕對無障礙!

全部評論

相關推薦

評論
1
7
分享

創(chuàng)作者周榜

更多
牛客網(wǎng)
??推髽I(yè)服務