原創2017-12-25創新教育研究中心TeachPlus C語言面試題 指針篇(一) 指針的使用,一直是c語言面試題中必考的部分, 因為指針本身使用的複雜性與普適性,所以考點非常多,而且也可以與其他知識相互結合, 因此我們將會使用五篇專題的篇幅來介紹指針。分析下麵的程式,指出程式中的錯誤: # i ...
原創2017-12-25創新教育研究中心TeachPlus
C語言面試題---指針篇(一)
指針的使用,一直是c語言面試題中必考的部分,
因為指針本身使用的複雜性與普適性,所以考點非常多,而且也可以與其他知識相互結合,
因此我們將會使用五篇專題的篇幅來介紹指針。分析下麵的程式,指出程式中的錯誤:
# include <stdio.h> int main( void) { char a; char *str=&a; strcpy(str,"hello"); printf("%s\n",str); return 0; }
本題解析
沒有正確為str分配記憶體空間,將會發生異常。
問題出在將一個字元串複製進一個字元變量指針所指地址。
雖然編譯的時候沒有報錯,但是在運行過程中,因為越界訪問了未被分配的記憶體,而導致段錯誤。
相關知識點
在處理與指針相關的問題時,首先需要搞明白的就是記憶體,因為指針操作的就是記憶體。
第一個,就是記憶體的分區。這也是經常會被考察的一個考點。
寫出記憶體分為幾大區域
對於這個問題,有幾種不不同的說法。
有的說記憶體分為五大分區,有的說分為四大分區,我們先來先看五個分區的說法:
認為記憶體分為五大分區的人,通常會這樣劃分:
1、BSS段( bss segment )
通常是指用來存放程式中未初始化的全局變量和靜態變量 (這里註意一個問題:一般的
書上都會說全局變量和靜態變量是會自動初始化的,那麼哪來的未初始化的變量呢?變量的
初始化可以分為顯示初始化和隱式初始化,全局變量和靜態變量如果程式員自己不初始化的話的確
也會被初始化,那就是不管什麽類型都初始化為0,這種沒有顯示初始化的就是我們這里所說的未初始化。
既然都是0那麼就沒必要把每個0都存儲起來,從而節省磁碟空間,這是BSS的主要作用)的一塊記憶體區域。
BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體分配。
BSS節不不包含任何數據,只是簡單的維護開始和結束的地址,即總大小。
以便記憶體區能在運行時分配並被有效地清零。BSS節在應用程式的二進位映象文件中並不存在,
即不占用磁碟空間而只在運行的時候占用記憶體空間 ,所以如果全局變量和靜態變量未初始化那麼其可執行文件要小很多。
2、數據段(data segment)
通常是指用來存放程式中已經初始化的全局變量和靜態變量的一塊記憶體區域。
數據段屬於靜態記憶體分配,可以分為只讀數據段和讀寫數據段。
字元串常量等,但一般都是放在只讀數據段中。
3、代碼段(code segment/text segment)
通常是指用來存放程式執行代碼的一塊記憶體區域。
這部分區域的大小在程式運行前就已經確定,
並且記憶體區域通常屬於只讀, 某些架構也允許代碼段為可寫,即允許修改程式。
在代碼段中,也有可能包含一些只讀的常數變量,例例如字元串常量等,但一般都是放在只讀數據段中 。
4、堆(heap)
堆是用於存放進程運行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。
當進程調用malloc等函數分配記憶體時,新分配的記憶體就被動態添加到堆上(堆被擴張);
當利用free等函數釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減)
5、棧 (stack)
棧又稱堆棧, 是用戶存放程式臨時創建的局部變量,也就是說我們函數括弧“{}” 中定義
的變量(但不不包括static聲明的變量,static意味著在數據段中存放變量)。
除此以外, 在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,
函數的返回值也會被存放回棧中。由於棧的先進先出特點,所以 棧特別方便用來保存/恢復調用現場。
從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的記憶體區。
而四大分區的說法,則這麼認為:
1、堆區:
由程式員手動申請,手動釋放,若不手動釋放,程式結束後由系統回收,生命周期是整個程式運
行期間。使用malloc或者new進行堆的申請,堆的總大小為機器器的虛擬記憶體的大小。
說明:new操作符本質上是使用了malloc進行記憶體的申請,new和malloc的區別如下:
(1)malloc是C語言中的函數,而new是C++中的操作符。
(2)malloc申請之後返回的類型是void*,而new返回的指針帶有類型。
(3)malloc只負責記憶體的分配而不會調用類的構造函數,而new不僅會分配記憶體,
而且會自動調用類的構造函數。
2、棧區:
由系統進行記憶體的管理理。主要存放函數的參數以及局部變量。
在函數完成執行,系統自行釋放棧區記憶體,不需要用戶管理。
整個程式的棧區的大小可以在編譯器器中由用戶自行設定,
VS中預設的棧區大小為1M,可通過VS手動更改棧的大。
64bits的Linux預設棧大小為10MB,可通過ulimit-s臨時修改。
3、靜態存儲區:
靜態存儲區內的變量在程式編譯階段已經分配好記憶體空間並初始化。這塊記憶體在程式的整個運行
期間都存在,它主要存放靜態變量、全局變量和常量。
註意:
(1)這里不區分初始化和未初始化的數據區,是因為靜態存儲區內的變量若不顯示初始化,
則編譯器會自動以預設的方式進行初始化,
即靜態存儲區內不存在未初始化的變量。
(2)靜態存儲區內的常量分為常變量和字元串常量,一經初始化,不可修改。
靜態存儲內的常變量是全局變量,與局部常變量不不同,
區別在於局部常變量存放於棧,實際可間接通過指針或者
引用進行修改,而全局常變量存放於靜態常量區則不可以間接修改。
(3)字元串常量存儲在靜態存儲區的常量區,字元串常量的名稱即為它本身,屬於常變量。
(4)數據區的具體劃分,有利利於我們對於變量類型的理理解。
不同類型的變數存放的區域不同。後面將以實例代碼說明這四種數據區中具體對應的變量。
4、代碼區:
存放程式體的二進位代碼。比如我們寫的函數,都是在代碼區的。