C语言指针入门 《C语言非常道》
C語言指針入門 《C語言非常道》
作為一個程序員,我接觸 C 語言有十年了。有的朋友讓我推薦 C 語言的參考書,我不敢亂推薦,尤其是國內作者寫的書,往往七拼八湊,漏洞百出。
但是,李忠老師的《C語言非常道》值得一讀。對了,李老師有個官網,網址是:
李忠老師官網
最棒的是,有配套的教學視頻,可以試看。
試看點這里
接下來言歸正傳,講解指針。以下內容很多都參考了李忠老師的《C語言非常道》,如果讀起來吃力的話,建議看視頻。
文章目錄
- C語言指針入門 《C語言非常道》
- 初識指針
- 取地址運算符和指針變量的聲明
- 指針指向什么類型很重要
- 解引用運算符
- 總結與補充
指針是 C 語言的難點,也是亮點。有人說如果不懂指針,那就不算是掌握了 C 語言。
作為一個嵌入式軟件工程師,我認為指針是 C 語言的殺手锏,離開了它,C 語言不可能在嵌入式領域“一覽眾山小”。
好了,進入正題。
初識指針
int a = 5;這句話定義了 int 類型的變量 a,并給它賦值 5;
在計算機執行這條語句的時候,會為變量 a 分配內存。
從此,這塊內存就和 a 聯系起來了,可以說變量名 a 就是這塊內存的化身。目前,這塊內存的存儲值是 5。
如果你要把存儲值修改為 8,你可以寫
a = 8;程序執行的時候,它自然會根據變量名 a 找到這塊內存,把里面存儲的值改為 8.
如果不知道這塊內存的名字是 a,你還能修改它的存儲值嗎?
方法還是有的,那就是通過“指針”。
其實在計算機眼中,內存是有地址的。要訪問某個內存單元,需要知道它的地址。如果把內存比喻成一排房子,那內存地址就是房子的門牌號碼。
如上圖所示,右邊標注的就是內存的地址(假設一個格子占 4 字節),變量 a 的內存地址就是 12.
如下圖所示,假設有個變量 b,它里面的內容剛好是變量 a 的內存地址(12),那么順著這個地址就可以找到變量 a.
紅色箭頭表示順著變量 b 的值(其實是 a 的地址——12)找到了變量 a.
你瞧,b 代表的值,像指針一樣,指向那個地址上的變量,鑒于這種類比特別形象,C 語言引入了指針類型,簡稱指針。圖中的變量 b 就是指針類型。
取地址運算符和指針變量的聲明
有人問,你怎么知道變量 a 的地址是 12 呢?
C 語言里面有個運算符——“&”,叫“取地址運算符”,用于取得某個變量的地址。要得到變量 a 的地址,可以這樣寫:&a
要想把 a 的地址保存在 b 中,可以這樣寫:
int *b; int a = 8; b = &a;第 1 行,定義了一個變量,變量名字是 b.
第 3 行,獲得變量 a 的地址,把這個地址存儲在變量 b 中。
int *b; 應該這樣理解:
首先,從標識符開始讀,因為標識符 b 的右邊是分號,所以要向左讀,左邊是 *,意思是指針,所以讀做 b 的類型是指針;
其次,對于指針這種類型來說,它指向的類型也很關鍵,我們繼續向左讀,遇到了“int”,所以讀“指向 int”
把粗體字連起來:b 的類型是指針,指向 int。
再比如:
int * p; // 注意,* 和 p 之間也可以有空格這句話定義了一個指針類型的變量 p,準確地說,p 的類型是指針,指向 int 類型,即 p 是一個指向 int 類型的指針變量。
上圖來自李忠老師的書——《C語言非常道》,告訴我們如何讀指針類型的聲明或定義。
注意:指針類型是個統稱,根據它所指向的類型,可細分為指向 char 的指針、指向 short 的指針、指向 int 的指針,等等。
要把變量 x 的地址保存在一個變量里,這個變量的類型必須是指針類型,而且,指針指向的類型必須和 x 的類型一致。例如,如果 x 是 char 類型,那么指向 x 的指針要聲明為 char * p;如果 x 是 double 類型,那么指向 x 的指針要聲明為 double * p;
指針指向什么類型很重要
有人會說:指針變量就是存儲地址的變量,順著這個地址,可以找到另一個變量,這個可以理解,但是為什么要強調指針指向的類型呢?
在 C 語言里,取地址運算符 & 的結果(值)并不單純是一個地址,而是一個包含了類型信息的地址。
例如前面提到的 &a,它確實可以計算變量 a 的地址,但是這個地址還包含了一個信息,即這個地址是用于訪問 int 類型變量的(因為 a 是 int 類型)。
為什么要附加一個類型信息呢?
前面我畫的內存圖示比較粗,現在細化一下。假設我的實驗環境下,int 類型的變量占 4 個字節,short 類型占 2 個字節,char 類型占 1 個字節?,F在定義 3 個變量,運行時的內存如下圖所示:
右邊標注的是內存地址,每個格子代表一個字節,你會發現內存地址是按照字節來編號的。
對于變量 a ,它占據了 4 個字節,即內存 12、13、14、15.
有人會問,那 a 的地址是多少?是 12 還是 13,還是 14,或者 15?
按照規定,a 的地址是它所占內存中編號最小的那個,即 12.
如果指針不含有類型信息,僅僅是一個地址(比如 12),那么順著這個地址去訪問內存,到底訪問多少字節呢?
舉個例子,假設要修改 a 的值為 100,如果不是按照 4 個字節來寫,而是按照 8 個字節來寫,那肯定會把變量 m 和 n 的值給覆蓋,這肯定不行。
所以,指針必須含有類型信息,這樣才能知道此地址指示的變量占用多大的內存,訪問的時候才不會出錯。
如圖所示,一旦知道了指針 b 所指向的類型是 int ,在訪問 a 的時候,就可以鎖定 12~15 這四個字節。
所以,一個指針是包含 2 個信息的:
基于以上 2 點,通過指針 b 間接訪問變量 a 成為可能,堪稱完美。
解引用運算符
如何通過 b 修改 a 的值呢?假設要通過 b 把 a 的值改為 100,可以這樣寫:
int *b; int a = 8; b = &a; *b = 100;第 4 行,b 左邊的這個 *,不代表指針,而是解引用運算符,也叫間接運算符。
前文已經說過,& 運算符用于取得變量的地址,而 * 運算符則根據一個地址來得到那個變量本身。也就是說, b 指向了哪個變量,*b 就代表那個變量。
所以,第 4 行的 *b = 100; 就相當于 a = 100;
* 和 & 在一起可以互相抵消, 例如 *&a 就等價于 a,你想,&a 表示一個指向 a 的指針,指針左邊加一個 *,就得到此指針指向的變量,于是又成了 a;
另外,&*b 等價于 b,因為 *b 就是 a,而 &a 就是 b.
總結與補充
相信有了前面的鋪墊,你再讀教科書上的文字會很有感覺。
以下幾點是總結和補充。
一元 & 運算符稱為取地址運算符,它需要一個右操作數,這個右操作數必須是變量或者函數。這是很自然的,只有內存中的變量或者函數才有地址,你不能取一個常量的地址,比如 & 250,這很荒唐。 一元 * 運算符則根據一個地址來得到那個變量(或者函數)本身 。(注意:指向函數的指針是進階內容,初學者可以忽略。)
“指針”這個詞其實有多種含義,需要根據上下文來區分。
1). 是一種類型,比如整形、浮點型等。指針這種類型特殊在它的值是一個內存地址,順著這個地址可以找到另一個變量。
2). 為方便起見,人們有時候也把指針類型的值叫作“指針”。 比如說, C 語言規定, 如果操作數的類型為 T,則一元 & 運算符的結果是指向 T 的指針。在這里,“指針”應該理解為“指針類型的值”。
3). 人們更經常地把指針類型的變量叫作指針,相對于“p 是一個指針類型的變量”,人們更喜歡說“p 是一個指針”。
為了還原指針所指向的變量或函數,需要使用一元 *運算符。 C 語言規定,一元 * 運算符的操作數必須是一個指針(即指針類型的變量或值), 如果此指針指向某變量,則一元 * 運算符的結果是個左值(你可以認為左值就是代表變量的表達式 ),代表指向的變量。
如果兩個指針指向的類型不同,則它們是不同的指針類型。
【end】
總結
以上是生活随笔為你收集整理的C语言指针入门 《C语言非常道》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql begin end 用法_超
- 下一篇: 五分钟了解先验概率和后验概率