<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          空指針,段錯誤,這場面試我栽倒在這里了!

          共 3550字,需瀏覽 8分鐘

           ·

          2020-08-09 01:03




          關(guān)注、星標(biāo)公眾號,直達(dá)精彩內(nèi)容

          ID:技術(shù)讓夢想更偉大

          作者:李肖遙


          面試官:滿頭的汗的,來面試的路一定很遠(yuǎn)吧?


          還好還好,騎車不到倆小時


          面試官:來先喝杯水,咱們面試不急,邊喝邊聊


          哇,謝謝您啦,咕隆咕隆喝下半杯


          面試官:那咱們開始吧,看你項(xiàng)目做的還不少啊,不錯不錯,咱們隨便聊聊。


          哇,“這面試官還不錯,感覺有戲”


          面試官:說說空指針NULL是本質(zhì)什么,與0一樣嗎


          嗯嗯,這個,NULL不就是0嗎?

          ?

          面試官:你確定是嗎,面帶微笑,淡定的眼神......


          嗯嗯,應(yīng)該是吧,,,不是吧,汗又開始冒起了來了......



          面試官:嗯嗯,了解了,不急慢慢喝水,我先上個廁所。


          水的滋潤與口水相互交織,騎車兩小時,面試3分鐘,這次我哉在這里了。

          ?



          NULL在C/C++中的標(biāo)準(zhǔn)定義

          NULL的標(biāo)準(zhǔn)定義

          #if?!defined(NULL)?&&?defined(__NEEDS_NULL)
          #ifdef?_cplusplus??????
          #define?NULL?0?????????//?這里對應(yīng)C++的情況
          #else
          #define?NULL?(void?*)0?//?這里對應(yīng)C語言的情況
          #endif

          編譯器預(yù)先定義了一個宏_cplusplus,來判斷當(dāng)前的編譯環(huán)境是C++的還是C語言的,在C++定義為0,在C語言中定義為(void *)0。

          在C/C++中的區(qū)別

          在C語言中,C中的“標(biāo)準(zhǔn)”寫法,NULL被替換為一個void* 類型的指針右值,值等于0;由于是void* 類型,可以隱式轉(zhuǎn)化為其它類型的指針。

          在C++中,void* 無法自由隱式轉(zhuǎn)換為其它類型的指針,而字面量0可以隱式轉(zhuǎn)換為指針類型。

          NULL 的本質(zhì)是什么

          我們從指針,空指針,空指針常量以及指向的內(nèi)存說起

          從指針角度來看

          我們看以下定義,p是一個函數(shù)內(nèi)的局部變量,則p的值是隨機(jī)的,也就是說p是一個野指針。

          int?func()
          {
          ??int?*p;?
          ??...
          }

          再看以下函數(shù),p是一個局部變量,分配在棧上的地址,p的值是(void *)0,實(shí)際就是0x00000000,意思就是指針p指向內(nèi)存的0x00000000地址處。這時候p就不是野指針了。

          int?func()
          {
          ??int?*p?=?NULL;?
          ??...
          }

          什么是空指針(null pointer)?

          如果將空指針常量轉(zhuǎn)換為指針類型,則保證生成的指針(稱為空指針)將不相等的值與指向任何對象或函數(shù)的指針進(jìn)行比較。

          定義char *p=0后,在之后p的任何一種賦值操作之后,p 都成為一個空指針,即p不指向任何實(shí)際的對象或者函數(shù)。反過來說,任何對象或者函數(shù)的地址都不可能是空指針。

          什么是空指針常量(null pointer constant)?

          值為0的整數(shù)常量表達(dá)式,或強(qiáng)制轉(zhuǎn)換為void *類型的表達(dá)式,稱為空指針常量

          空指針(null pointer)指向了哪里的內(nèi)存

          這里標(biāo)準(zhǔn)沒有定義,取決于系統(tǒng)的實(shí)現(xiàn)。我們常見的空指針一般指向0x00000000地址,即空指針的內(nèi)部用全0x00000000來表示,也有一些系統(tǒng)用一些特殊的地址值或者特殊的方式表示空指針。

          在我們實(shí)際寫代碼時,關(guān)鍵點(diǎn)在于判斷哪個是空指針。

          NULL 有什么作用

          在大部分的CPU中,內(nèi)存的0x00000000地址處都不是可以隨便訪問的,所以野指針指向了這個區(qū)域可以保證野指針有個安家之所,否則會發(fā)生段錯誤。

          當(dāng)你嘗試訪問的時候會阻止你,但是有些地址不是只讀的,如果一個指針指向了這個地址,你又在不經(jīng)意間修改了它,可能會導(dǎo)致一些重要的文件被修改,所以指針初始化成NULL是有必要的。

          注意不要混用'\0' 和 '0' 和 0 ?和 NULL

          • '\0'是一個轉(zhuǎn)義字符,他對應(yīng)的ASCII編碼值是0,本質(zhì)就是0;常用于表示字符串的結(jié)尾標(biāo)志,以判斷字符串有沒有到頭。
          • '0'是一個字符,他對應(yīng)的ASCII編碼值是48,本質(zhì)是48。
          • 0是一個int類型的數(shù)字,本質(zhì)就是0。
          • NULL是一個表達(dá)式,是強(qiáng)制類型轉(zhuǎn)換為void *類型的0,一般用來比較指針是否是一個野指針。

          NULL是不是0呢

          NULL 就是0?

          我們先來看以下代碼:

          //https://tool.lu/coderunner/
          #include
          int?main()
          {????
          ??int?*p=NULL;????
          ??printf("%s",p);?
          }

          結(jié)果如下:

          輸出(null) ,在執(zhí)行int *p=NULL,打印出來空白,實(shí)際上p的值為0x00000000,在C語言中,NULL的本質(zhì)是0,但是這個0不是當(dāng)一個整形數(shù)據(jù)來解析,而是當(dāng)一個內(nèi)存地址來解析的,代表的是內(nèi)存的0地址。

          (void *)0這個整體表達(dá)式表示一個指針,地址在哪里取決于指針變量本身,這個指針變量指向0地址(實(shí)際是0地址開始的一段內(nèi)存)。

          NULL 不是0?

          如果一個指針被賦予NULL,相當(dāng)于這個指針執(zhí)行了0x00000000這個邏輯地址,但是在C語言中0x0000這個邏輯地址用戶是不能使用的,所以當(dāng)你試圖取一個指向了NULL的指針的內(nèi)容時,就會提示段錯誤,測試一下代碼如下:

          //https://tool.lu/coderunner/
          //來源:技術(shù)讓夢想更偉大
          //作者:李肖遙
          #include
          int?main()
          {????
          ?
          ?int?*node?=?NULL;
          ?int?p?=?0;
          ?p?=?*node;
          ?printf("%d\n",p);
          ?
          ?return?0;
          }

          編譯結(jié)果如下:

          由于指針node執(zhí)行的是NULL,也就是邏輯地址0x00000000,而這個地址不能訪問,所以編譯器提示段錯誤。

          那么看到這里你覺得NULL還是0嗎?根據(jù)宏定義我們知道:(void *)0表示把數(shù)值0強(qiáng)制轉(zhuǎn)換為void *類型,所以最后運(yùn)行結(jié)果為0。

          變量在定義時,系統(tǒng)會給他分配內(nèi)存空間,指針變量也是一樣,如果指針沒有指向的話,那么地址就是隨機(jī)值,如果不小心用的話就會導(dǎo)致數(shù)據(jù)錯誤,從而使程序退出。

          NULL 使指針p指向地址0x00000000,在大多數(shù)系統(tǒng)中都將0x00000000作為不被使用的地址,所以運(yùn)用p也不會毀壞數(shù)據(jù)。

          但也有系統(tǒng)會使用地址0x00000000,而將 NULL 定義為其他值,所以不要把 NULL 和 0 等同起來。

          我們使用值傳遞的方式來看,在網(wǎng)上有一個面試題,這里我參考一下代碼,能夠幫助大家更好的理解,其代碼如下:

          //https://tool.lu/coderunner/
          //來源:技術(shù)讓夢想更偉大
          //作者:李肖遙
          #include?

          void?vPassByFun(int?*node)
          {
          ????static?int?N?=?1024;
          ????node?=?&N;
          }

          int?main()
          {
          ?
          ????int?*node?=?NULL;
          ????int?p?=?0;
          ????vPassByFun(node);
          ????p?=?*node;
          ?
          ????printf("%d\n",p);
          ????
          ????return?0;
          }

          輸出結(jié)果如下:

          vPassByFun函數(shù)是值傳遞,node指針變量的值并不受影響,所以這個程序的效果和上一個程序運(yùn)行結(jié)果都是段錯誤。

          如果要讓結(jié)果為1024,應(yīng)該怎樣寫代碼呢?我們來這樣寫代碼:

          //https://tool.lu/coderunner/
          //來源:技術(shù)讓夢想更偉大
          //作者:李肖遙
          #include?

          void?vPassByFun(int?**?node)
          {
          ????static?int?N?=?1024;
          ????*node=&N;
          }

          int?main()
          {
          ?
          ????int?*node?=?NULL;
          ????int?p?=?0;

          ????vPassByFun(&node);
          ????p?=?*node;

          ????printf("%d\n",p);
          ?
          ????return?0;

          }

          運(yùn)行結(jié)果如下:

          傳遞一個二級指針也就是傳遞node指針變量的指針給vPassByFun函數(shù),這樣的話結(jié)果就對了。

          最后

          編碼過程中,我們需要對自己的指針負(fù)責(zé),往往導(dǎo)致bug出現(xiàn)或者找不到問題所在地的就是這種細(xì)節(jié)。最后,原創(chuàng)不易,希望能夠改正文章的錯誤,多提意見留言,謝謝。

          推薦閱讀:


          嵌入式編程專輯
          Linux 學(xué)習(xí)專輯
          C/C++編程專輯

          關(guān)注微信公眾號『技術(shù)讓夢想更偉大』,后臺回復(fù)“m”查看更多內(nèi)容,回復(fù)“加群”加入技術(shù)交流群。

          長按前往圖中包含的公眾號關(guān)注

          瀏覽 41
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩精品大香蕉 | 国产精品二区高清在线苍井空 | 已婷婷狠狠18禁久久YY | 波多野结衣一区二区三区免费视频 | 字幕一区二区久久人妻网站 |