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" (為何不是亂碼?)
}
a[] = "abc":編譯器將字串常值 "abc" 放在唯讀資料段,a 是堆疊上的陣列,複製 常值內容到堆疊。return a:回傳堆疊位址,函數返回後堆疊框架失效,p 成為懸空指標。set() 呼叫:新的堆疊框架剛好覆蓋 相同位置,寫入 "123"。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或智慧指標管理記憶體。