雙十一過完了吧,兜兒裡都沒錢了吧,可以安心學習了吧,正好萬眾期待的指針章節開始了,快來那知識來充實下自己~
講完數組之後有點拖拉了,但是更新到指針的我真的不敢怠慢了,如果指針也是之前的那種更新速度的話,估計大家會看的很暈,因為知識都不連貫了嘛~
內容提要
本文主要講述在內存中是如何存放變量的,指針與指針變量,如何定義一個指針變量,指針的取址運算符和取值運算符,未初始化指針的兩大危險。全文約 1800 字,閱讀完畢約 10 分鐘。
內存是如何存放變量的?
通過變量名對變量進行訪問和存儲是為了方便程序員而設計的,其實在內存中完全沒有存儲變量名的必要。因為編譯器知道具體每一個變量名對應的存放地址,所以當你讀取某個變量的時候,編譯器就會找到變量名所在的地址,並根據變量的類型讀取相應範圍的數據,比如下面這張圖
在上圖中,左側表示變量名與地址之間的關係,右邊表示地址與存放的值之間的關係。我們可以看到,變量名 f 對應一個地址10005,123 佔據了10005-10008 的 4 個地址(因為 C 語言中的 int 型變量佔據 4 個字節)。所以可以根據地址和數據的類型,來確定具體存放的是什麼。
2指針和指針變量
通常我們所說的指針,就是地址的意思。C 語言中有專門的指針變量用於存放指針,跟普通變量不同,指針變量存儲的是一個地址。指針變量也有類型,它的類型就是存放的地址指向的數據類型。比如說下面的這張圖
在上圖中分為三個部分,最左邊是變量名與地址之間的關係,a - g 很好理解,和之前一樣,代表每一個變量的變量名都對應著一個地址,其中需要注意的是我們又定義了兩個指針變量:pa 和 pb,因為它們是指針變量,所以它們在內存中也是存放於某個地址中。
由上圖左側可知,指針變量被存放在地址 11000中;指針變量是佔 4 個字節的空間,也就是說一個地址是佔 4 個字節的空間,所以指針變量中存放的是 10000;又由於指針變量存放的是變量的地址,所以指針指向的是 ‘F’ 。同樣可以知道,指針變量 pf 存放的是 123 的地址。
定義指針變量
定義指針變量跟普通變量十分相似,只是中間多了一個星號(*)。
上圖中左側的數據類型 表示指針變量中存放的地址指向的內存單元的數據類型。比如指針變量 pa 中存放字符變量 a 的地址,所以 pa 應該定義為字符型指針;而指針變量 pb 中存放的是整型變量 f 的地址,所以 pb 就定義為整型指針。
在這裡就涉及到指針變量最關鍵的兩個元素,地址和步長。指針變量存放的只是變量的首地址,要讀出變量還需要知道步長,步長可以由數據類型確定。因為不同數據類型所佔的內存空間不同,如果指定錯誤了,那麼在訪問指針變量指向的數據時就會出錯。
取址運算符和取值運算符
如果需要獲取某個變量的地址,可以使用取地址運算符(&),下面是定義一個指針並進行初始化的過程
如果需要訪問指針變量指向的數據,可以使用取值運算符(*)
這裡要注意的是取值運算符跟定義指針用的都是星號(*),這屬於符號的重用,在定義時表示定義一個指針變量;在其他位置表示獲取指針變量指向的變量的值。直接通過變量名來訪問變量的值,我們稱之為
直接訪問;通過指針變量這樣的形式來訪問變量的值,我們稱之為間接訪問,所以取值運算符有時候也叫間接運算符。在這裡其實可以看到,初始化指針和對指針取值可以看作是一個互為相反的過程。初始化是將一個地址賦值給指針變量(如 pa = &a;),而要修改指針所對應變量的值的操作,就需要取值操作(如 *pa=b)。
避免訪問未初始化指針
對於類似於下邊這樣的代碼是很危險的
因為指針變量 a 到底指向哪裡是未知的,這個道理就跟訪問未初始化的變量一樣,它的值是隨機的。所以就有可能引發下面這種兩種危險。
首先像上面那樣,對一個未知地址進行賦值,就可能覆蓋掉系統的一些關鍵代碼。不過你也別高興得太早,因為系統通常都不會允許你這麼幹,程序這時候會被終止並報錯。
更危險的是,偶爾這個指針變量裡隨機存放的是一個合法的地址,那麼接下來的賦值就會導致那個位置的值莫名其妙地被修改。這種類型的 Bug 是非常難以排查的。所以,在對指針進行間接訪問時,必須確保它們已經被正確地初始化。
好啦~就到這裡了,如果我哪裡沒有講明白,歡迎積極留言哦~
參考
[1] “小甲魚” 視頻課程《帶你學C帶你飛》【第一季】P21
-----------------
1.回覆【圖書】:獲取15本新手自學編程,零基礎入門經典學習教材;
2.回覆【我要造輪子】:獲取100多本計算機類經典書籍;
3.回覆【開發工具】:獲取幾大主流編程語言的開發工具~
4.回覆【內推】:可幫你內推到大廠工作。
閱讀更多 譚慶波不在家 的文章