首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ 函數呼叫堆疊深度解析:為何區域陣列指標回傳後仍能正確列印?

     編輯:程式設計綜合問答

程式碼現場

char* get() {
    char a[] = "abc";  // 區域陣列,儲存在堆疊
    return a;          // 回傳堆疊位址 → 未定義行為 (UB)
}
void set() {
    char b[] = "123";  // 另一個區域陣列
}
void main() {
    char* p = get();
    cout << p << endl;  // 輸出 "abc" (看似正常)
    set();
    cout << p << endl;  // 輸出 "abc" (為何不是亂碼?)
}

記憶體佈局真相

  1. a[] = "abc":編譯器將字串常值 "abc" 放在唯讀資料段,a 是堆疊上的陣列,複製 常值內容到堆疊。
  2. return a:回傳堆疊位址,函數返回後堆疊框架失效,p 成為懸空指標。
  3. set() 呼叫:新的堆疊框架剛好覆蓋 相同位置,寫入 "123"。
  4. 第二次 cout << p:未定義行為。此處輸出 "abc" 純屬巧合——編譯器優化將字串常值合併,p 實際指向資料段的 "abc",而非堆疊副本。

驗證實驗

char* get() {
    char a[] = "abc";
    a[0] = 'X';  // 嘗試修改 → 若指向資料段會崩潰 (SIGSEGV)
    return a;
}

若崩潰,證明 a 確實在堆疊;若不崩潰且輸出 "Xbc",則編譯器最佳化將 a 直接綁定到資料段 (違反標準但常見)。

正確做法

// 1. 靜態儲存期
char* get_static() {
    static char a[] = "abc";  // 資料段,生命週期 = 程式執行期
    return a;
}

// 2. 動態配置 (呼叫端負責 free)
char* get_dynamic() {
    char* a = malloc(4);
    strcpy(a, "abc");
    return a;
}

// 3. C++ 風格:回傳 std::string (RAII,最推薦)
std::string get_modern() { return "abc"; }

核心結論

「區域陣列指標回傳」是 C/C++ 經典 UB。看似正確的輸出不代表程式正確,換編譯器、優化等級、加上其他函數呼叫都可能導致崩潰或輸出亂碼。永遠使用 std::string、std::vector 或智慧指標管理記憶體。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved