C 語言中「函數能否返回局部變量」是經典面試題,也是新手易踩的坑。結論先行:返回局部變量的值是安全的,返回局部變量的地址(指針)是危險的。本文從內存模型角度深度剖析。
char *returnStr() {
char *p = "hello world!"; // 字符串字面量存放在只讀數據段(.rodata)
return p;
}
解析: 字符串常量具有靜態存儲期,程序全生命週期有效,返回其地址完全安全。
char *returnStr() {
char p[] = "hello world!"; // 棧上分配的數組
return p; // 返回棧地址!
}
後果: 函數返回後棧幀銷毀,調用者拿到的是無效地址,打印可能出現亂碼、崩潰或看似正常(偶然未被覆蓋)。
int func_val() { int a = 10; return a; } // ✅ 安全:返回副本
int *func_ptr() { int a = 10; return &a; } // ❌ 危險:返回棧地址
// 靜態局部變量例外
int *func_static() { static int a = 10; return &a; } // ✅ 安全:靜態存儲區
若函數內需創建對象供外部使用,正確模式:
// 方式1:調用者分配,函數填充(推薦)
void fill_buffer(char *buf, size_t len) { ... }
// 方式2:函數分配,調用者負責釋放(需文檔註明)
char *create_string() { return strdup("hello"); } // 調用者必須 free()
// 方式3:C++ 返回 std::string / std::vector(RAII 自動管理)
std::string modern_way() { return "hello"; }
| 場景 | 存儲區 | 返回值 | 返回指針 |
|---|---|---|---|
| 局部自動變量 | 棧 | ✅ 安全 | ❌ 危險 |
| 局部靜態變量 | 數據段 | ✅ 安全 | ✅ 安全 |
| 字符串常量 | 只讀數據段 | N/A | ✅ 安全 |
| malloc/new 分配 | 堆 | N/A | ✅ 安全(需手動釋放) |
最佳實踐: 能用值返回就用值返回;必須返回指針時,優先考慮靜態變量、調用者預分配緩衝區、或 C++ 智慧指標/容器。嚴禁返回棧上對象的地址。