1. 程式人生 > >16. C語言 -- 指標

16. C語言 -- 指標

本部落格主要內容為 “小甲魚” 視訊課程《帶你學C帶你飛》【第一季】 學習筆記,文章的主題內容均來自該課程,在這裡僅作學習交流。在文章中可能出現一些錯誤或者不準確的地方,如發現請積極指出,十分感謝。
也歡迎大家一起討論交流,如果你覺得這篇文章對你有所幫助,記得評論、點贊哦 ~(。・∀・)ノ゙

1. 記憶體是如何存放變數的?

  通過變數名對變數進行訪問和儲存是為了方便程式設計師而設計的,其實在記憶體中完全沒有儲存變數名的必要。因為編譯器知道具體每一個變數名對應的存放地址,所以當你讀取某個變數的時候,編譯器就會找到變數名所在的地址,並根據變數的型別讀取相應範圍的資料。比如下面這張圖

在這裡插入圖片描述

在上圖中,左側表示變數名與地址之間的關係,右邊表示地址與存放的值之間的關係。我們可以看到,變數名 f 對應一個地址10005,123 佔據了10005-10008 的 4 個地址(因為 C 語言中的 int 型變數佔據 4 個位元組)。所以可以根據地址和資料的型別,來確定具體存放的是什麼。

2. 指標和指標變數

  通常我們所說的指標,就是地址的意思。C 語言中有專門的指標變數用於存放指標,跟普通變數不同,指標變數儲存的是一個地址指標變數也有型別,它的型別就是存放的地址指向的資料型別。比如說下面的這張圖

在這裡插入圖片描述

在上圖中分為三個部分,最左邊是變數名與地址之間的關係,a - g 很好理解,和之前一樣,代表每一個變數的變數名都對應著一個地址,其中需要注意的是我們又定義了兩個指標變數:pa 和 pb,因為它們是指標變數,所以它們在記憶體中也是存放於某個地址中。由上圖左側可知,指標變數被存放在地址 11000中;指標變數是佔 4 個位元組的空間,也就是說一個地址是佔 4 個位元組的空間,所以指標變數中存放的是 10000;又由於指標變數存放的是變數的地址,所以指標指向的是 ‘F’ 。同樣可以知道,指標變數 pf 存放的是 123 的地址。

3. 定義指標變數

  定義指標變數跟普通變數十分相似,只是中間多了一個星號(*)。

char *pa;
int *pb;

左側的資料型別表示指標變數中存放的地址指向的記憶體單元的資料型別。比如剛才的圖中,指標變數 pa 中存放字元變數 a 的地址,所以 pa 應該定義為字元型指標;而指標變數 pb 中存放的是整型變數 f 的地址,所以 pb 就定義為整型指標。這點一定要注意,因為不同資料型別所佔的記憶體空間不同,如果指定錯誤了,那麼在訪問指標變數指向的資料時就會出錯。

4. 取地址運算子和取值運算子

  如果需要獲取某個變數的地址,可以使用取地址運算子(&),下面是定義一個指標並進行初始化的過程

// 其中 a 和 f 時已經存在的變數
char *pa = &a;
int *pb = &f;

// 也可以寫成如下的形式
char *pa;
pa = &a;

如果需要訪問指標變數指向的資料,可以使用取值運算子(*)

printf("%c, %d\n", *pa, *pb);

這裡要注意的是取值運算子跟定義指標用的都是星號(*),這屬於符號的重用,在不同的地方有不同的意義:在定義時表示定義一個指標變數;在其他位置表示獲取指標變數指向的變數的值。直接通過變數名來訪問變數的值,我們稱之為直接訪問;通過指標變數這樣的形式來訪問變數的值,我們稱之為間接訪問,所以取值運算子有時候也叫間接運算子

  在這裡其實可以看到,初始化指標和對指標取值可以看作是一個互為相反的過程。初始化是將一個地址賦值給指標變數(如 pa = &a;),而要修改指標所對應變數的值的操作,就需要取值操作(如 *pa=b)。

5. 避免訪問未初始化的指標

#include <stdio.h>

int main()
{
    int *a;
    *a = 123;

    return 0;
}

  類似於上邊這樣的程式碼是很危險的,因為指標變數 a 到底指向哪裡,我們沒辦法知道。這個道理就跟訪問未初始化的變數一樣,它的值是隨機的。這在指標變數裡會很危險,因為後邊程式碼對一個未知地址進行賦值,那麼你可能會覆蓋到系統的一些關鍵程式碼。不過你也別高興得太早,因為系統通常都不會允許你這麼幹,程式這時候會被終止並報錯。更危險的是,偶爾這個指標變數裡隨機存放的是一個合法的地址,那麼接下來的賦值就會導致那個位置的值莫名其妙地被修改。這種型別的 Bug 是非常難以排查的。所以,在對指標進行間接訪問時,必須確保它們已經被正確地初始化

6. 本節內容概要

  本節的主要內容如下,指標就是記憶體中的地址;指標變數適用於存放指標的變數,即存放地址的變數;指標變數的型別是變數中存放的地址對應的資料的型別;指標變數作為一個變數,本身有一個地址,它的地址中儲存的是另一個變數的地址。

參考

[1] “小甲魚” 視訊課程《帶你學C帶你飛》【第一季】P21

歡迎大家關注我的知乎號(左側)和經常投稿的微信公眾號(右側)
在這裡插入圖片描述