一.指針和引用的概念

指針:指針是一個變量,其值為另一個變量的內存地址。我們可以通過指針來間接訪問和修改它所指向的變量的值。

代碼語言:javascript

AI代碼解釋

int main() {
    int x = 10;
    int* ptr = &x;  // 指針ptr指向x的地址
    cout << "x的值: " << x << endl;       // 直接訪問x
    cout << "x的地址: " << &x << endl;    // 輸出x的地址
    cout << "ptr的值: " << ptr << endl;   // 輸出ptr存儲的地址(即x的地址)
    cout << "ptr指向的值: " << *ptr << endl;  // 通過指針訪問x的值
    *ptr = 20;  // 通過指針修改x的值
    cout << "修改後x的值: " << x << endl;
    return 0;
}

引用:引用是已存在變量的別名,它與被引用的變量共享同一內存地址。引用一旦初始化後,就不能再指向其他變量。

代碼語言:javascript

AI代碼解釋

int main() {
    int x = 10;
    int& ref = x;  // ref是x的引用(別名)
    cout << "x的值: " << x << endl;
    cout << "ref的值: " << ref << endl;
    cout << "x的地址: " << &x << endl;
    cout << "ref的地址: " << &ref << endl;  // 與x的地址相同
    ref = 20;  // 通過引用修改x的值
    cout << "修改後x的值: " << x << endl;
    return 0;
}

二.指針與引用的核心區別

1. 聲明與初始化
  • 指針:使用*聲明,可以不初始化(但不推薦),也可以初始化為nullptr

代碼語言:javascript

AI代碼解釋

int* ptr1;       // 未初始化的指針(危險)
int* ptr2 = nullptr;  // 空指針
int x = 5;
int* ptr3 = &x;  // 指向x的指針
  • 引用:使用&聲明,必須在創建時初始化,且不能初始化為nullptr

代碼語言:javascript

AI代碼解釋

int x = 5;
int& ref1 = x;   // 正確,ref1是x的引用
// int& ref2;    // 錯誤,引用必須初始化
// int& ref3 = nullptr;  // 錯誤,不能將引用初始化為空
2. 可修改性
  • 指針:可以改變指向的對象

代碼語言:javascript

AI代碼解釋

int x = 5, y = 10;
int* ptr = &x;
ptr = &y;  // 指針現在指向y
  • 引用:一旦綁定到某個對象,就不能再綁定到其他對象

代碼語言:javascript

AI代碼解釋

int x = 5, y = 10;
int& ref = x;
ref = y;  // 這是將y的值賦給x,而不是讓ref引用y
3. 空值
  • 指針:可以為空(nullptr),表示不指向任何對象

代碼語言:javascript

AI代碼解釋

int* ptr = nullptr;  // 空指針
  • 引用:不能為空,必須始終引用一個有效的對象。不存在 "空引用" 的概念
4. 內存佔用
  • 指針:需要佔用內存空間來存儲地址(通常為 4 字節或 8 字節,取決於系統)
  • 引用:在語法層面不佔用內存空間,它只是一個別名。編譯器通常會使用指針來實現引用,但這是編譯器內部的事情,對程序員是透明的。
5. 操作符
  • 指針:使用*運算符訪問指向的對象,使用->運算符訪問指向對象的成員

代碼語言:javascript

AI代碼解釋

struct Person {
    string name;
    int age;
};
Person p{"Alice", 30};
Person* ptr = &p;
cout << ptr->name << endl;  // 使用->訪問成員
cout << (*ptr).age << endl; // 先解引用再用.訪問成員
  • 引用:直接使用.運算符訪問成員,無需解引用

代碼語言:javascript

AI代碼解釋

Person p{"Bob", 25};
Person& ref = p;
cout << ref.name << endl;  // 直接使用.訪問成員
6. 多級訪問

指針:支持多級指針(指針的指針)

代碼語言:javascript

AI代碼解釋

int x = 5;
int* ptr = &x;
int**ptr_ptr = &ptr;  // 指向指針的指針
cout << ** ptr_ptr << endl;  // 輸出5

引用:不支持多級引用,不存在 "引用的引用"


三.指針與引用的共同點

  1. 都可以間接訪問和修改所指向 / 引用的變量
  2. 都可以作為函數參數,實現參數的 "傳址" 效果,允許函數修改實參的值
  3. 都可以指向 / 引用堆上分配的內存
何時使用指針,何時使用引用?
使用引用的場景:
  1. 函數參數傳遞,尤其是對於大型對象,可以避免拷貝開銷,同時不希望參數為 null
  2. 函數返回值,當函數需要返回容器元素或對象成員的訪問權時
  3. 操作符重載(如operator=),使語法更自然

代碼語言:javascript

AI代碼解釋

// 引用作為函數參數
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}
// 引用作為函數返回值
vector vec = {1, 2, 3};
int& get_element(int index) {
    return vec[index];  // 返回向量元素的引用
}
使用指針的場景:
  1. 需要表示 "空" 的情況(可以使用nullptr
  2. 需要改變指向的目標時
  3. 處理動態分配的內存
  4. 實現數據結構(如鏈表、樹等)
  5. 函數需要返回多個值時(通過指針參數)

代碼語言:javascript

AI代碼解釋

// 指針表示空值
int* find(int* arr, int size, int target) {
    for (int i = 0; i < size; i++) {
        if (arr[i] == target) {
            return &arr[i];
        }
    }
    return nullptr;  // 未找到,返回空指針
}
// 動態內存分配
int* create_array(int size) {
    return new int[size];  // 返回指向新分配數組的指針
}

指針和引用都是 C++ 中用於間接訪問變量的重要工具,它們各有特點和適用場景:

  • 指針更靈活,可以為空,可以改變指向,但使用不當容易引發錯誤
  • 引用更安全,必須初始化且不能為 null,語法更簡潔,但靈活性較低