解引用NULL为什么会导致程序挂死?
來源:公眾號【編程珠璣】
作者:守望先生
ID:shouwangxiansheng
解引用NULL指針為什么會出錯,導致程序掛死?或者說訪問內存地址為0的位置為什么會視為非法?
先了解NULL
參考《NULL,0,'\0'有何區別?》。
解引用NULL
解釋問題之前,先描述問題。請看下面的代碼:
#include<stdio.h> int?main(void) {char?*p?=?NULL;char?c?=?*p;return?0; }運行:
Segmentation?fault為什么會出現這樣的錯誤呢?解釋這個問題之前,先簡單了解以下程序地址空間布局。
程序地址空間布局
本文不深入介紹,而僅簡單介紹進程的虛擬地址空間(注意下面提到的都不是實際的物理地址),以便幫助我們理解標題的問題。
程序運行起來后,會映射到一個虛擬地址空間。對于32位程序,它是一個4G的大小(一個32位程序,能用到的內存也不過4G)。
其布局如下:
程序空間地址
內核空間:大小與操作系統有關,對于Linux系統,32位程序的內核空間默認為1G(可調整)。
棧:Linux下默認為8M,可調整。具有自動存儲期的變量存儲在棧中。
堆:不會超過3G,所以有人問你,一直malloc,最多能申請多少,應該有數了吧?
DATA :數據區
TEXT:代碼區
關于不同類型的變量,其存儲區域可以參考《全局變量,靜態全局變量,局部變量,靜態局部變量》。
當然,這些都不是本文的重點,本文的重點在于0的位置。可以看到,地址為0的位置,既不是在堆中,也不是在棧中,或者說不是一個能正常訪問的位置。
問題所在
對于程序來說,它只能訪問一些特定的位置,例如堆棧,而諸如內核空間,0等位置是受保護的,不允許程序進行訪問,因此一旦程序中嘗試訪問了這樣的地址,就會觸發保護機制,最終可能直接讓程序退出。
下面的例子也是類似的:
//來源:公眾號【編程珠璣】 #include?<stdio.h> int?main(void) {char?*p?=?"hello";p[0]?=?'H';return?0; }字符串hello存儲在了只讀數據區,因此嘗試修改它就會導致程序崩潰。
$?gcc?-o?test?test.c $?./test Segmentation?fault?(core?dumped) $?readelf?test?-x??.rodata??#查看只讀數據段 Hex?dump?of?p?'.rodata':0x00400570?01000200?68656c6c?6f00??????????????....hello.總結來說,就是當程序訪問了不允許訪問,或者使用了錯誤訪問(只讀卻想寫)方式的時候,程序就要受到懲罰了。
所以有時候可以通過地址值來粗略的判斷其訪問區域是否合法。例如打印的指針地址大于0xc0000000,那么你就知道可能可能訪問了內核區域。當然對于64位程序,它不是這樣的,64位程序0xffff,8000,0000,0000以上地址為內核空間。
總結
不該讀的地方別讀,不該寫的地方不要寫,解引用記得做空檢查。
掃碼或長按關注
回復「?籃球的大肚子」進入技術群聊
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的解引用NULL为什么会导致程序挂死?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 0基础可以考CPDA数据分析师证书吗
- 下一篇: 关于在联想电脑管家更新网卡驱动后无法显示