1. 直接創建 C++ 使用 new 創建二維數組最直接的方法就是 new T[M][N]。返回的指針類型是 T (*)[N],它是指向數組的指針,可以直接使用數組下標形式訪問元素。釋放記憶體直接使用delete[]。示例代碼: #include <iostream> class A { public ...
1. 直接創建
C++ 使用 new 創建二維數組最直接的方法就是 new T[M][N]
。返回的指針類型是 T (*)[N]
,它是指向數組的指針,可以直接使用數組下標形式訪問元素。釋放記憶體直接使用delete[]
。示例代碼:
#include <iostream>
class A
{
public:
A()
{
std::cout << "A::A" << std::endl;
}
~A()
{
std::cout << "A::~A" << std::endl;
}
int x;
};
int main()
{
A (*p)[3] = new A[2][3];
delete[] p;
}
執行結果:
A::A
A::A
A::A
A::A
A::A
A::A
A::~A
A::~A
A::~A
A::~A
A::~A
A::~A
可以看到 A 的構造函數和析構函數正常執行。如果覺得 T (*)[N]
繁瑣,可以直接使用 auto p = new T[M][N]
。三維數組甚至更高維數組都可以使用這種方法。例如,三維數組使用 new T[M][N][O]
進行創建,依舊使用 delete[] p
進行釋放。
為什麼可以這樣寫?因為這種多維數組和普通的多維數組都是通過一維數組實現的。例如,int a[6][8]
,實際上編譯器會轉化為 int b[6 * 8]
一維數組。然後每次訪問二維數組 a[i][j]
相當於訪問 b[i * 8 + j]
。從二維、三維數組的轉化過程中可以發現一些規律。
T a[M][N] --> T b[M * N], a[i][j] --> b[i * N + j]
T a[M][N][O] --> T b[M * N * O], b[i][j][k] --> b[i * N * O + j * O + k]
編譯器進行下標轉換時,並沒有用到第 0 維的大小,而其它維的大小都是必須的。這也就是為什麼下麵代碼能正確執行。
int a[2][3];
int (*p)[3] = a;
由於多維數組本質上是一維數組,所以釋放記憶體都是 delete[] p
,而沒有奇怪的 delete[][]
語法。
2. 藉助指針數組
還有一種方法就是先 new T*[M]
創建一個指針數組,其每個元素保存每一行的首個元素的地址,再使用 new T[N]
創建每一行。示例代碼如下:
A** p = new A*[2];
for (int i = 0; i < 2; ++i) {
p[i] = new A[3];
}
for (int i = 0; i < 2; ++i) {
delete[] p[i];
}
delete[] p;
這種方法非常繁瑣,首先 new T*[M]
不能寫成 new (T(*)[M])
,因為它是指針數組而不是數組指針。其次,需要對每一行調用 new T[N]。釋放記憶體時,要先使用 delete[]
釋放每一行,再調用 delete[]
釋放數組指針。這幾個步驟一步都不能錯,不然就出現野指針或者記憶體泄漏。這段代碼我也是用 Address Sanitizer 和 Leak Sanitizer 檢查一遍才寫對。
這種方法唯一的好處就是可以創建交錯數組(Jagged Array),也就是每一行的大小不一樣。例如:
A **p = new A *[2];
p[0] = new A[3];
p[1] = new A[4];
for (int i = 0; i < 2; ++i)
{
delete[] p[i];
}
delete[] p;
3. 藉助 std::vector
可以用 std::vector 對上面這種方法進行包裝,使其更加易用。示例代碼如下:
std::vector<std::vector<int>> v{ std::vector<int>(3), std::vector<int>(4) };
std::cout << v[0].size() << " " << v[1].size() << std::endl;
這段代碼創建了一個二維數組,第 0 行有 3 個元素,第 1 行有 4 個元素。這種方法既能創建交錯數組,也不需要手動釋放記憶體。
本文來自博客園,作者:mkckr0,轉載請註明原文鏈接:https://www.cnblogs.com/mkckr0/p/17045233.html