歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> 嵌入式linux面試題解析(二)――C語言部分二

嵌入式linux面試題解析(二)――C語言部分二

日期:2017/3/3 11:05:22   编辑:Linux技術

嵌入式linux面試題解析(二)――C語言部分二

1、.h頭文件中的ifndef/define/endif 的作用?答:防止該頭文件被重復引用。

2、#include 與 #include “file.h”的區別?

答:前者是從Standard Library的路徑尋找和引用file.h,而後者是從當前工作路徑搜尋並引用file.h。

3、描述實時系統的基本特性

答 :在特定時間內完成特定的任務,實時性與可靠性。

4、全局變量和局部變量在內存中是否有區別?如果有,是什麼區別?

答 :全局變量儲存在靜態數據區,局部變量在堆棧中。

5、堆棧溢出一般是由什麼原因導致的?

答 : A、沒有回收垃圾資源

B、層次太深的遞歸調用

6、不能做switch()的參數類型

答 :switch的參數不能為實型。

7、局部變量能否和全局變量重名?

答:能,局部會屏蔽全局。要用全局變量,需要使用”::”

局部變量可以與全局變量同名,在函數內引用這個變量時,會用到同名的局部變量,而不會用到全局變量。對於有些編譯器而言,在同一個函數內可以定義多個同名的局部變量,比如在兩個循環體內都定義一個同名的局部變量,而那個局部變量的作用域就在那個循環體內。

8、如何引用一個已經定義過的全局變量?

答 :可以用引用頭文件的方式,也可以用extern關鍵字,如果用引用頭文件方式來引用某個在頭文件中聲明的全局變量,假定你將那個變量寫錯了,那麼在編譯期間會報錯,如果你用extern方式引用時,假定你犯了同樣的錯誤,那麼在編譯期間不會報錯,而在連接期間報錯。

9、全局變量可不可以定義在可被多個.C文件包含的頭文件中?為什麼?

答 :可以,在不同的C文件中以static形式來聲明同名全局變量。

可以在不同的C文件中聲明同名的全局變量,前提是其中只能有一個C文件中對此變量賦初值,此時連接不會出錯。

10、do……while和while……有什麼區別?

答 :前一個循環一遍再判斷,後一個判斷以後再循環。

11、程序的內存分配

答:一個由C/C++編譯的程序占用的內存分為以下幾個部分

A、棧區(stack)―由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。

B、堆區(heap)―一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。

C、全局區(靜態區)(static)―全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。程序結束後由系統釋放。

D、文字常量區―常量字符串就是放在這裡的。程序結束後由系統釋放。

E、程序代碼區―存放函數體的二進制代碼

12、解釋堆和棧的區別

答:堆(heap)和棧(stack)的區別

A、申請方式

stack:由系統自動分配。例如,聲明在函數中一個局部變量int b;系統自動在棧中為b開辟空間

heap:需要程序員自己申請,並指明大小,在c中malloc函數

如p1=(char*)malloc(10);

但是注意p1本身是在棧中的。

B、申請後系統的響應

棧:只要棧的剩余空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。

堆:首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多余的那部分重新放入空閒鏈表中。

C、申請大小的限制

棧:棧是向低地址擴展的數據結構,是一塊連續的內存的區域,即棧頂的地址和棧的最大容量是系統預先規定好的,linux系統可以使用ulimit -a命令查看當前系統的棧的大小,默認為10M(64位系統),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。

堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。

D、申請效率的比較:

棧:由系統自動分配,速度較快。但程序員是無法控制的。

堆:是由malloc分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.

E、堆和棧中的存儲內容

棧:在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變量。注意靜態變量是不入棧的。當本次函數調用結束後,局部變量先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。

堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容由程序員安排。

F、存取效率的比較

char s1[]=”aaaaaaaaaaaaaaa”;

char *s2=”bbbbbbbbbbbbbbbbb”;

aaaaaaaaaaa是在運行時刻賦值的;

而bbbbbbbbbbb是在編譯時就確定的;

但是,在以後的存取中,在棧上的數組比指針所指向的字符串(例如堆)快。

比如:

#include

void main()

{

char a=1;

char c[]=”1234567890″;

char *p=”1234567890″;

a = c[1];

a = p[1];

return;

}

對應的匯編代碼

10:a=c[1];

004010678A4DF1mov cl,byteptr[ebp-0Fh]

0040106A884DFCmov byteptr[ebp-4],cl

11:a=p[1];

0040106D8B55ECmov edx,dwordptr[ebp-14h]

004010708A4201mov al,byteptr[edx+1]

004010738845FCmov byteptr[ebp-4],al

第一種在讀取時直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,在根據edx讀取字符,顯然慢了。

13、什麼是預編譯,何時需要預編譯?

答:預編譯又稱為預處理,是做些代碼文本的替換工作。處理#開頭的指令,比如拷貝#include包含的文件代碼,#define宏定義的替換,條件編譯等,就是為編譯做的預備工作的階段,主要處理#開始的預編譯指令,預編譯指令指示了在程序正式編譯前就由編譯器進行的操作,可以放在程序中的任何位置。

GCC編譯系統在對程序進行通常的編譯之前,先進行預處理。GCC提供的預處理功能主要有以下三種:宏定義、文件包含、條件編譯

使用場合如下: A、總是使用不經常改動的大型代碼體。

B、程序由多個模塊組成,所有模塊都使用一組標准的包含文件和相同的編譯選項。在這種情況下,可以將所有包含文件預編譯為一個預編譯頭。

14、描述內存分配方式以及它們的區別?

答: A、從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static 變量。

B、在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集。

C、從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程序員自己負責在何時用free 或delete 釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但問題也最多

15、簡述數組與指針的區別?

答:數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。指針可以隨時指向任意類型的內存塊。

A、修改內容上的差別

char a[] = “hello”;

a[0] = ‘X’;

char *p = “world”; // 注意p 指向常量字符串

p[0] = ‘X’; // 編譯器不能發現該錯誤,運行時出現段錯誤

B、用運算符sizeof 可以計算出數組的容量(字節數)。sizeof(p),p 為指針得到的是一個指針變量的字節數,而不是p 所指的內存容量。C++/C 語言沒有辦法知道指針所指的內存容量,除非在申請內存時記住它。注意當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。

char a[] = “hello world”;

char *p = a;

cout<< sizeof(a) << endl; // 12 字節

cout<< sizeof(p) << endl; // 4 字節

計算數組和指針的內存容量

void Func(char a[100])

{

cout<< sizeof(a) << endl; // 4 字節而不是100 字節

}

16、論述含參數的宏與函數的優缺點

答:

帶參 宏函數

處理時間 編譯時 程序運行時

參數類型 沒有參數類型問題 定義實參、形參類型

處理過程 不分配內存 分配內存

程序長度 變長 不變

運行速度 不占運行時間 調用和返回占用時間

17、寫一個“標准”宏

答:交換兩個參數值的宏定義為:. #define SWAP(a,b)\

(a)=(a)+(b);\

(b)=(a)-(b);\

(a)=(a)-(b);

輸入兩個參數,輸出較小的一個:

#define MIN(A,B) ((A) < (B))? (A) : (B))

表明1年中有多少秒(忽略閏年問題):

#define SECONDS_PER_YEAR (60UL* 60 * 24 * 365)

已知一個數組table,用一個宏定義,求出數據的元素個數

#define NTBL (sizeof(table)/sizeof(table[0]))

18、A.c 和B.c兩個c文件中使用了兩個相同名字的static變量,編譯的時候會不會有問題?這兩個static變量會保存到哪裡(棧還是堆或者其他的)?

答: static的全局變量,表明變量僅在本模塊中有意義,不會影響其他模塊。

存放在靜態數據區,但是編譯器對他們的命名是不同的。

如果要使變量在其他模塊也有意義的話,需要使用extern關鍵字。

19、下面的代碼輸出是什麼,為什麼?

void foo(void)

{

unsigned int a = 6;

int b = -20;

(a+b > 6) ? puts(“> 6″) : puts(“<= 6");

}

當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換為無符號類型。因此-20變成了一個非常大的正整數,所以該表達式計算出的結果大於6。

20、交換兩個變量的值,不使用第三個變量。

即a=3,b=5,交換之後a=5,b=3;

有兩種解法, 一種用算術算法, 一種用^(異或)

a = a + b;

b = a - b;

a = a - b;

or

a = a^b;// 只能對int,char..

b = a^b;

a = a^b;

or

a ^= b ^= a;

本文出自 “生命不息,奮斗不止” 博客,轉載請與作者聯系!

Copyright © Linux教程網 All Rights Reserved