C/C++ 中陣列名在表達式中會退化為指向首元素的指針,但函數返回類型不能是陣列。初學者常犯錯:在函數內定義區域陣列並返回其指針,導致棧內存釋放後讀取垃圾值。本文通過矩陣乘法實例,逐步演示錯誤現象、new/delete 動態分配法、輸出參數法(推薦)、以及現代 C++ std::array/std::vector 最佳實踐。
float* MultMatrix(float A[4], float B[4]) {
float M[4]; // 區域陣列,棧上分配
// ... 計算 ...
return M; // 錯誤!函數結束,M 內存失效
}
運行結果首行正確(棧未被覆寫),後續行全是亂碼(6.5e-039 等非正規化數),且每次運行結果不穩定。
new[] 動態分配 + 調用方 delete[]float* MultMatrix(float A[4], float B[4]) {
float* M = new float[4]; // 堆上分配,生命週期由程式員控制
M[0] = A[0]*B[0] + A[1]*B[2];
M[1] = A[0]*B[1] + A[1]*B[3];
M[2] = A[2]*B[0] + A[3]*B[2];
M[3] = A[2]*B[1] + A[3]*B[3];
return M; // 返回堆地址,安全
}
int main() {
float A[4] = {1.75, 0.66, 0, 1.75};
float B[4] = {1, 1, 0, 0};
float* M = MultMatrix(A, B);
// 使用 M...
delete[] M; // 必須釋放,否則記憶體洩漏
}
缺點:所有權轉移不明確,易忘 delete[];異常拋出時洩漏;需文檔約定「調用方負責釋放」。
void MultMatrix(float M[4], const float A[4], const float B[4]) {
M[0] = A[0]*B[0] + A[1]*B[2];
M[1] = A[0]*B[1] + A[1]*B[3];
M[2] = A[2]*B[0] + A[3]*B[2];
M[3] = A[2]*B[1] + A[3]*B[3];
}
int main() {
float A[4] = {1.75, 0.66, 0, 1.75};
float B[4] = {1, 1, 0, 0};
float* M = new float[4]; // 或棧上 float M[4];
MultMatrix(M, A, B);
// 使用 M...
delete[] M; // 若用 new
}
優勢:內存管理責任清晰(誰分配誰釋放),無所有權轉移困惑,異常安全,效能最高(無額外分配/拷貝)。
std::array / std::vectorstd::array(C++11)#include <array>
std::array<float, 4> MultMatrix(const std::array<float, 4>& A,
const std::array<float, 4>& B) {
std::array<float, 4> M;
M[0] = A[0]*B[0] + A[1]*B[2];
M[1] = A[0]*B[1] + A[1]*B[3];
M[2] = A[2]*B[0] + A[3]*B[2];
M[3] = A[2]*B[1] + A[3]*B[3];
return M; // 值語義,自動拷貝/移動,零開銷
}
std::vectorstd::vector<float> MultMatrix(const std::vector<float>& A,
const std::vector<float>& B) {
// 假設 2x2 矩陣扁平化存儲
std::vector<float> M(4);
// ... 計算 ...
return M; // 移動語義(C++11),極高效
}
若需返回 N x M 矩陣,建議封裝 Matrix 類,內部用 std::vector<float> 一維存儲,重載 operator() 實現 mat(i,j) 訪問,並提供 rows()/cols()。避免 float** 或 float[][M] 等易錯寫法。
| 方案 | 適用場景 | 記憶體管理 | 現代 C++ 推薦度 |
|---|---|---|---|
| 返回區域陣列指針 | ❌ 絕不使用 | 未定義行為 | ⭐ |
new[] + delete[] | C 風格舊代碼維護 | 手動,易洩漏 | ⭐⭐ |
| 輸出參數 | 高效能、C/C++ 混編、嵌入式 | 調用方完全控制 | ⭐⭐⭐⭐ |
std::array | 編譯期已知固定大小 | RAII,值語義 | ⭐⭐⭐⭐⭐ |
std::vector | 運行期確定大小 | RAII,移動語義 | ⭐⭐⭐⭐⭐ |
std::array/std::vector),利用移動語義消除拷貝開銷。