| 方式 | 位置 | 生命周期 | 管理 |
| 靜態存儲區 | 全局/靜態變量 | 程序全程 | 自動 |
| 棧 | 局部變量 | 函數調用期間 | 自動(幀指針) |
| 堆 | malloc/new | 程序員控制 | 手動free/delete |
動態內存傳遞本質是堆內存所有權的轉移。
指針操作標準流程
int *p = NULL; // 1. 初始化為NULL
p = new int(3); // 2. 分配/指向對象
if (p != NULL) { *p = 5; } // 3. 使用前檢查非空
delete p; // 4. 釋放
p = NULL; // 5. 置NULL防野指針
三種正確傳遞模式
模式一:C++ 引用傳遞(推薦,最安全直觀)
void MyFunc(char* &pReturn, size_t size) { // 參數為指針的引用
pReturn = (char*)malloc(size);
memset(pReturn, 0, size);
if (size >= 13) strcpy(pReturn, "Hello World!");
}
int main() {
char *pMyReturn = NULL;
MyFunc(pMyReturn, 15); // 直接傳遞指針變量
if (pMyReturn) {
puts(pMyReturn);
free(pMyReturn);
pMyReturn = NULL;
}
}
char* &pReturn綁定實參pMyReturn本身,而非副本
- 函數內修改
pReturn直接修改pMyReturn
- 語法清晰,無解引用干擾,C++首選
模式二:二級指針(C語言標準模式)
void MyFunc(char **pReturn, size_t size) {
*pReturn = (char*)malloc(size);
// 或 *pReturn = new char[size];
}
int main() {
char *pMyReturn = NULL;
MyFunc(&pMyReturn, 100); // 傳遞指針地址
if (pMyReturn) {
strcpy(pMyReturn, "hello");
puts(pMyReturn);
free(pMyReturn);
pMyReturn = NULL;
}
}
- 傳遞
&pMyReturn(類型char**)
- 函數通過
*pReturn = ...解引用一次,修改一級指針值
- 本質:傳遞指針變量的地址,實現「傳址調用」效果
- C語言標準做法,廣泛用於輸出參數
模式三:函數返回值直接返回指針
char* MyFunc() {
char *p = (char*)malloc(20);
memset(p, 0, 20);
return p; // 返回分配的地址
}
int main() {
char *str = MyFunc();
if (str) {
strcpy(str, "Hello, baby");
puts(str);
free(str);
str = NULL;
}
}
- 最簡潔,調用點
str = MyFunc()語義清晰
- 注意:不能返回棧上數組或字符串字面量地址
- 錯誤示例:
char* f() { return "Hello"; } → 返回靜態存儲區字面量,不可free、不可修改
對比總結
| 模式 | 語言 | 語法複雜度 | 所有權語義 | 適用場景 |
| 引用 | C++ | 低 | 清晰(輸出參數) | C++項目首選 |
| 二級指針 | C/C++ | 中 | 明確(傳地址) | C項目、C接口、需兼容C |
| 返回值 | C/C++ | 最低 | 隱含(調用者接管) | 單一輸出、工廠函數 |
內存管理鐵律(必須內化為肌肉記憶)
- 誰分配,誰負責釋放(或明確文檔移交所有權)
- 分配後立即檢查NULL,失敗路徑不使用指針
- 釋放後立即置NULL,防止野指針二次釋放/訪問
- 避免多重所有權:單一指針擁有內存,或用智能指針/引用計數
- 跨模塊接口:同一模塊分配並釋放(CRT堆隔離問題),或提供專用釋放函數
現代 C++ RAII 替代方案(徹底消除手動管理)
#include
#include
#include
// 1. 單對象
std::unique_ptr create_int() { return std::make_unique(42); }
// 2. 動態數組
std::unique_ptr create_array(size_t n) {
auto arr = std::make_unique(n);
for (size_t i=0; i create_vec(size_t n) {
std::vector v(n);
for (size_t i=0; i
總結
動態內存傳遞的核心難點在於指針值的修改需要傳遞指針的地址(二級指針)或綁定引用。C++項目優先用引用參數或返回智能指針/容器,C項目標準化二級指針輸出參數模式。建立「分配-檢查-使用-釋放-置NULL」完整鏈路,配合代碼審查與靜態分析工具,將內存錯誤壓制在編譯期/測試期。
- 上一篇文章: C語言函數返回數組的兩種正確姿勢:指針返回與結構體封裝
- 下一篇文章: C語言可變參數宏va_list/va_start/va_arg/va_end完整指南:原理、用法與實現機制
Copyright ©
程式碼之家 All Rights Reserved