C++ 學習筆記(3):引用和指標

AurLemon發表於2024-12-01

前言

前幾天問 GPT 問的,單獨拎出來當作筆記的一個補充吧。

指標的基本概念

指標(Pointer) 是一個變數,它儲存的是另一個變數的記憶體地址。在 C++ 中,定義一個指標變數時使用 * 符號,這個符號並不是表示解引用,而是表示這個變數是一個指標變數,指向某種型別的資料。

例子

int a = 5;
int* p = &a;  // p 是一個指向 a 的指標,&a 獲取 a 的地址

在上面的例子中,&a 表示獲取 a 的記憶體地址,而 int* p 表示定義一個指向 int 型別的指標變數 p*p 表示解引用,訪問指標 p 指向的記憶體位置中的資料。

解引用的概念

解引用(Dereferencing) 是指透過指標訪問它指向的記憶體地址中的內容。當你使用 *p 時,你是在訪問指標 p 儲存的地址所指向的資料,而不是地址本身。

例子

int a = 5;
int* p = &a;  // p 儲存 a 的地址
cout << *p;    // 解引用 p,輸出 5,因為 p 指向 a

重要概念: *p 代表解引用,訪問的是指標 p 所指向記憶體位置中的資料,而不是 p 本身。也就是說,*p 是訪問 a 的值(即 5),而 p 只是儲存了 a 的地址。

引用與指標的區別

引用(Reference) 只是某個物件的別名,透過引用,你直接操作原始物件的資料。引用變數不儲存記憶體地址,只是對已有物件的別名,不能為 null 或空指標。

例子

int a = 5;
int& ref = a;  // ref 是 a 的引用
ref = 10;      // 修改 ref 的值,a 變為 10
cout << a;     // 輸出 10,a 被修改了

在這個例子中,ref 直接代表 a修改 ref 就等於修改 a。沒有像指標那樣透過解引用去訪問,引用的操作更直接、簡潔。

常見誤解:*p = &x*p 的使用

我前面提到了一個問題,就是:為什麼 *p = &x 不成立,而 *p 作為解引用操作並沒有做到“放地址”。這實際是理解上的一個小誤區。

關鍵點

定義指標時,*p 是用來宣告指標的型別,它告訴編譯器 p 是一個指向某型別(如 int)的指標。而 &x 是取地址操作,表示你要拿到 x 變數的記憶體地址。

*p = &x 其實是錯誤的,因為 *p 不是儲存地址的地方,它應該儲存的是,而不是一個地址。正確的做法是:

  int x = 10;
  int* p = &x;   // p 儲存的是 x 的地址
  *p = 20;        // 解引用 p,把 x 的值改成 20
  cout << x;      // 輸出 20,x 的值被修改了

正確理解: 當你用 *p 進行解引用時,它實際上是指向 p 所指向的記憶體位置的內容。所以 *p 用於訪問指標指向的物件的值,而不是用來放地址的

引用與指標的比較

特性 引用(Reference) 指標(Pointer)
定義時初始化 必須在定義時初始化,一旦初始化後無法改變。 可以初始化為 nullptr,並且可以隨時改變指向的物件。
儲存內容 儲存物件的別名,沒有獨立的記憶體地址。 儲存的是一個記憶體地址,指向某個物件。
是否為空 不可以為空,引用必須繫結到一個物件。 可以為空(nullptr),也可以指向不同的物件。
訪問方式 直接使用引用變數名即可訪問原始物件。 使用 * 運算子解引用來訪問指標所指向的內容。
是否可以改變 一旦繫結,引用無法指向其他物件。 可以改變指標指向的物件,甚至指向 nullptr
適用場景 適用於不需要重新繫結的物件,通常用於修改物件的值。 適用於需要靈活指向不同物件、動態記憶體分配和處理連結串列等。

例子:引用和指標的操作對比

#include <iostream>
using namespace std;

void byReference(int& ref) {
    ref = 10;  // 透過引用修改原始值
}

void byPointer(int* p) {
    *p = 20;  // 透過指標解引用修改原始值
}

int main() {
    int a = 5;
    int b = 15;
    
    byReference(a);  // a 透過引用傳遞給函式,a 變為 10
    byPointer(&b);    // b 透過指標傳遞給函式,b 變為 20

    cout << "a: " << a << endl;  // 輸出 a: 10
    cout << "b: " << b << endl;  // 輸出 b: 20
    
    return 0;
}

引用:直接作為別名運算元據,語法簡單且無需解引用。指標:儲存的是地址,需要透過解引用來訪問指向的資料,使用時更靈活。

常見的使用場景

引用 常用於函式引數傳遞(避免傳值開銷),或者需要直接修改原始物件的場景。指標 常用於動態記憶體分配(newdelete)、資料結構(連結串列、樹)、以及需要操作多個物件或空指標的場景。

總結

指標 是一個變數,它儲存了某個物件的記憶體地址,並且透過 * 來解引用,訪問或修改指向的物件的內容。引用 是某個物件的別名,它直接代表物件本身,不需要解引用操作,操作簡潔。在 定義指標時*p 只是用來告訴編譯器 p 是一個指標型別變數,而 解引用 是透過 *p 訪問指標指向的內容。

相關文章