首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 數組參數傳遞本質:退化為指針、長度丟失、引用保持長度與現代容器替代

     編輯:C++ 入門

核心鐵律:數組參數退化為指針

C++ 函數參數聲明為數組類型時,**編譯器隱式轉換為指針類型**。以下三個聲明**完全等價**:


void func(int* arr);        // 指針
void func(int arr[]);       // 數組 (無長度)
void func(int arr[10]);     // 數組 (有長度,但被忽略!)

本質:調用時數組表達式退化為指向首元素的指針 (&arr[0])。**長度信息在函數簽名中完全丟失**。

三大後果與對策

1. 函數內修改影響原數組 (傳引用語義)


void modify(int arr[]) { arr[0] = 99; } // 修改原數組首元素
int main() {
    int a[3] = {1,2,3};
    modify(a); // a[0] 變為 99
}

對策:若不想修改,參數聲明 const int arr[] 或 const int* arr。

2. 函數不知數組長度 → 緩衝區溢出風險


void unsafe(int arr[10]) { 
    // 編譯器不檢查實參長度!
    arr[9] = 0; // 若實參只有 3 元素 → 越界寫入,未定義行為
}
int main() {
    int small[3] = {0};
    unsafe(small); // 編譯通過,運行崩潰/靜默破壞
    int* ptr = new int[5];
    unsafe(ptr);   // 合法但危險
    delete[] ptr;
}

3. 傳遞長度的兩種傳統機制

機制代碼優點缺點
額外長度參數void func(int arr[], size_t n)簡單、C兼容易參數不匹配、無類型安全
哨兵值 (C字符串)void func(const char* str) (以 \0 結尾)無需長度參數僅適用字符串、不可含嵌入空字符

現代 C++ 解決方案:保持長度信息的類型

1. 數組引用參數 (C++ 核心特性)


// 參數為「10個int的數組的引用」
void func(int (&arr)[10]) { 
    // 編譯器強制實參必須是 int[10]!
    static_assert(std::extent_v == 10); // 編譯期獲取長度
}

int main() {
    int a[10] = {};
    func(a);    // OK
    int b[5] = {};
    // func(b); // 編譯錯誤:類型不匹配 (int[5] vs int[10])
    int* p = a;
    // func(p); // 編譯錯誤:指針非數組
}

優勢:編譯期強制長度匹配、函數內可用 sizeof(arr) 獲取完整大小、std::size(arr) (C++17) 獲取長度。

2. std::array (C++11) — 封裝定長數組


#include 
#include 

void func(std::array& arr) {
    std::sort(arr.begin(), arr.end()); // 迭代器、算法全支持
    std::cout << arr.size(); // 10
}

int main() {
    std::array arr = {1,2,3,4,5,6,7,8,9,0};
    func(arr); // 傳引用,零開銷
    // std::array arr2; func(arr2); // 編譯錯誤:類型不同
}

特點:值語義 (可拷貝/賦值)、棧分配、長度是類型一部分、標準容器接口。

3. std::vector / std::span (C++20) — 動態/視圖


#include 
#include  // C++20

// 接受任意連續序列 (array, vector, C數組, new[])
void modern_func(std::span s) {
    std::cout << "Size: " << s.size() << std::endl;
    for (int v : s) std::cout << v << ' ';
}

int main() {
    int carr[10] = {};
    std::vector vec = {1,2,3};
    std::array arr = {};
    
    modern_func(carr);  // OK,自動推導長度 10
    modern_func(vec);   // OK,長度 3
    modern_func(arr);   // OK,長度 5
    modern_func({1,2,3,4}); // OK,臨時初始化列表 (C++20)
}

std::span 是現代 C++ 接受連續序列的統一標準參數類型:無所有權、輕量視圖、保留長度、兼容所有連續容器。

總結:數組參數最佳實踐

  1. 禁用裸數組參數:void f(int arr[]) 等同 void f(int*),長度丟失、不安全。
  2. 定長數組:用 std::array (有所有權) 或 T (&arr)[N] (引用現有數組)。
  3. 不定長/動態序列:用 std::span (C++20, 首選視圖) 或 std::vector& (需所有權/擴容)。
  4. C 接口交互:邊界處用 span 構造 {ptr, len},內部用 span。
  5. 模板通用算法:用迭代器對或 std::ranges (C++20)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved