c語言基礎面試題

1、statac 全局變數、局部變數、函式與普通全局變數、局部變數、函式static 全局變數與普通的全局變數有什麼區別?static 局部變數和普通局部變數有什麼區別?static 函式與普通函式有什麼區別?

答 、全局變數(外部變數)的說明之前再冠以 static 就構成了靜態的全局變數。全局變數本身就是靜態存儲方式, 靜態全局變數當然也是靜態存儲方式。 這兩者在存儲方式上並無不同。

這兩者的區別雖在於非靜態全局變數的作用域是整個源程式, 當一個源程式由多個源檔案組成時,非靜態的全局變數在各個源檔案中都是有效的。 而靜態全局變數則限制了其作用域, 即只在定義該變數的源檔案內有效, 在同一源程式的其它源檔案中不能使用它。由於靜態全局變數的作用域局限於一個源檔案內,只能為該源檔案內的函式公用, 因此可以避免在其它源檔案中引起錯誤。

從以上分析可以看出, 把局部變數改變為靜態變數後是改變了它的存儲方式即改變了它的生存期。把全局變數改變為靜態變數後是改變了它的作用域, 限制了它的使用範圍。

static 函式與普通函式作用域不同。僅在本檔案。只在當前源檔案中使用的函式應該說明為內部函式(static),內部函式應該在當前源檔案中說明和定義。對於可在當前源檔案以外使用的函式,應該在一個頭檔案中說明,要使用這些函式的源檔案要包含這個頭檔案static 全局變數與普通的全局變數有什麼區別:static 全局變數只初使化一次,防止在其他檔案單元中被引用;

static 局部變數和普通局部變數有什麼區別:static 局部變數只被初始化一次,下一次依據上一次結果值;

static 函式與普通函式有什麼區別:static 函式在記憶體中只有一份,普通函式在每個被調用中維持一份拷貝

2、程式的記憶體分配

答:一個由 c/c++編譯的程式占用的記憶體分為以下幾個部分

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

2、堆區(heap)—一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由 os 回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鍊表,呵呵。

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

4、文字常量區—常量字元串就是放在這裡的。程式結束後由系統釋放。

5、程式代碼區—存放函式體的二進制代碼

3、解釋堆和棧的區別

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

(1)申請方式

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

heap:需要程式設計師自己申請,並指明大小,在 c 中 malloc 函式

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

在 c++中用 new 運算符

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

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

(2)申請後系統的回響

棧:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢出。

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

(3)申請大小的限制

棧:在 windows 下,棧是向低地址擴展的數據結構,是一塊連續的記憶體的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 windows 下,棧的大小是 2m(也有的說是 1m,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示 overflow。因此,能從棧獲得的空間較小。

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

(4)申請效率的比較:

棧:由系統自動分配,速度較快。但程式設計師是無法控制的。

堆:是由 new 分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便.另外,在 windows 下,最好的方式是用 virtual alloc 分配記憶體,他不是在堆,也不是在棧,而是直接在進程的地址空間中保留一塊記憶體,雖然用起來最不方便。但是速度快,也最靈活。

(5)堆和棧中的存儲內容

棧:在函式調用時,第一個進棧的是主函式中後的下一條指令(函式調用語句的下一條可執行語句)的地址,然後是函式的各個參數,在大多數的 c 編譯器中,參數是由右往左入棧的,然後是函式中的局部變數。注意靜態變數是不入棧的。

當本次函式調用結束後,局部變數先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函式中的下一條指令,程式由該點繼續運行。

堆:一般是在堆的頭部用一個位元組存放堆的大小。堆中的具體內容由程式設計師安排。

(6)存取效率的比較

char s1[]="aaaaaaaaaaaaaaa";

char *s2="bbbbbbbbbbbbbbbbb";

aaaaaaaaaaa 是在運行時刻賦值的;

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

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

比如:

#include

voidmain()

{

char a=1;

char c[]="1234567890";

char *p="1234567890";

a = c[1];

a = p[1];

return;

}

對應的彙編代碼

10:a=c[1];

004010678a4df1movcl,byteptr[ebp-0fh]

0040106a884dfcmovbyteptr[ebp-4],cl

11:a=p[1];

0040106d8b55ecmovedx,dwordptr[ebp-14h]

004010708a4201moval,byteptr[edx+1]

004010738845fcmovbyteptr[ebp-4],al

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