C++數組概述
基本概念
1. 數組是固定大小的一種複合類型
- 因爲數組是固定大小,所以在編譯期間就決定了基大小
- 數組的內存是連續(無論是一維數組還是多維數組)
2. 數組的特性
- 數組之間不允許拷貝和賦值
- 數組名是常指針
數組的操作
1. 數組的初始化
- 數組定義時不初始化,則會被初始化爲未初始化值
int nArr[4]; // 當數組爲全局變量時,未初始化值默認爲0;當數組爲局部變量時,則其值在Debug下爲0xccccccc,Release下爲隨機值
- 大括號顯式初始化
int nArr1[4] = {1, 2, 3, 4};
int nArr2[4] = {1, 2, 3}; // 第4值默認爲0
int nArr3[] = {1, 2, 3, 4}; // 編譯器在編譯階段推斷數組維數爲4
int nArr4[][4] = {1, 2, 3, 4, 5, 6, 7, 8}; // 數組最高維可以在編譯階段推導出爲2
int nArr5[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; // 數組最高維可以在編譯階段推導出爲2
int nArr6[][4] = {{1}, {5}}; // 數組最高維可以在編譯階段推導出爲2,剩下的默認爲0
int nArr7[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; // 數組大小與賦值必須匹配
- 字符數組
char szArr[] = "abcd"; // 編譯器在編譯階段推斷數組維數爲5
2. 數組的大小
int nArr1[4] = {0}; // sizeof(nArr1)爲16,因爲nArr1是int[4]類型
int nArr2[3][4] = {0}; // sizeof(nArr2)爲48,因爲nArr2是int[3][4]類型
3. 數組與引用
int nArr6[][4] = {{1}, {2}, {3}}; // 數組最高維可以在編譯階段推導出爲2,剩下的默認爲0
int (&nArr7)[4] = nArr6[1]; // nArr7即是nArr6[2]的引用
int nArr8[4] = {0};
int (&nArr9)[4] = nArr8; // nArr9即是nArr8的引用
4. 數組與指針
int nArr1[4] = {0};
int nArr2[3][4] = {0};
int *p1 = nArr1;
int *p2 = nArr2[1];
int *p3 = &nArr2[1][0]; // p2,p3是相等的
int (*p4)[4] = nArr2; // 此處的數組名nArr2退化爲指針,p4是指針,指向int [4]類型數組首地址
int (*p5)[4] = &nArr2[0]; // p4,p5也是相等的
int *p6[4]; // p6是數組,存放4個int類型指針。sizeof(p6)=16
int* p7[4]; // 因爲[]的優先級最高,所以p6,p7是相同的
5. 數組類型別名
typedef int intArray[4];
typedef int int2DArray[3][4];
intArray arr1 = {0};
int arr2[4] = {0};
// arr1,arr2是等價的
int2DArray arr3 = {0};
int arr4[3][4] = {0};
// arr3,arr4是等價的
6. 數組作爲函數參數
-值與數組 因爲數組不能拷貝,所以數組理論上不能作爲值傳遞的形參。但事實上,我們有看到直接用數組作爲參數值傳遞的,這明顯違背數組拷貝的原理。如下段代碼,其實是特殊情況,arr
其實並不是數組類型,arr
在作爲形參時已經自動退化成指針了。
void Test(int arr[4])
{
*arr = 4;
int nSize = sizeof(arr); // 因爲arr退化成指針,所以nSize=4
}
void Test1(int arr[])
{
int nSize = sizeof(arr); // 因爲arr退化成指針,所以arr[]的維數寫不寫無影響
}
void Test2(int arr[][4])
{
int nSize = sizeof(arr); // 因爲arr退化成指針,所以arr[]的維數寫不寫無影響,nSize=4
}
void Test3(int (*arr)[4])
{
int nSize = sizeof(arr); // Test3和Test4是等價的
}
- 引用與數組
數組類型的引用是合法的,引用類型的數組是非法的。
void Test(int (&arr)[4])
{
int nSize = sizeof(arr); // 因爲arr是int [4]類型,所以nSize=20,此處維數不能省
}
void Test1(int &arr[4]) // Error,arrays of references are illegal
{
}
- 指針與數組
void Test(int (*arr)[4])
{
int nSize = sizeof(arr); // arr是指針,指向int [4]首地址
}
void Test1(int* arr[4])
{
int nSize = sizeof(arr); // arr看起來是int* [4]類型,是數組,但是數組不能拷貝,所以退化成指針
}
void Test2(int* arr[])
{
int nSize = sizeof(arr); // arr[]退化成指針,Test2和Test1造價,nSize=4
}
7. 數組作爲函數返回值
- 返回值 因爲返回值也會生成拷貝,所以與數組不能拷貝相違背,所以數組值不能作爲函數返回。
- 返回引用
引用的數組是非法的,所以只能返回數組的引用
int (&Test)() [4] // 返回的值優先引用,然後因爲數組的引用,所以數組在引用後
{
int nArr[4] = {1, 2, 3, 4};
return nArr;
}
int (&nTemp)[4] = Test();
// 上面返回引用的方式難理解,我們可以換一種方式
typedef int intArray[4];
intArray& Test() // 利用typdef簡單數組類型
{
int nArr[4] = {1, 2, 3, 4};
return nArr;
}
intArray& nTemp = Test();
// C++11引用了類型推導,可以用下面形式
int nArr[4] = {0, 1, 2, 3};
decltype(nArr)& Test23()
{
return nArr;
}
- 返回指針
因爲數組不能拷貝,所以不能返回指針類型的數組(int* [4]
),但可以返回指向數組的指針。
int nArr[3][4] = {{4}, {1, 5}, {2}};
int (*Test())[4]
{
int (*pArr)[4] = nArr;
return pArr;
}
int (*pArr)[4] = Test();
// 用typedef,C++11也可以用decltype(代碼略)
typedef int intArray[4];
int nArr[3][4] = {{4}, {1, 5}, {2}};
intArray* Test()
{
int (*pArr)[4] = nArr;
return pArr;
}
intArray* pArr = Test();
8. 數組與vector
- 異同
- 相同點,數組與vector的內存都是連續的。
- 不同點,數組是固定大小,而vector是動態大小。
- 相互轉化
數組可以看作是特殊的vector,所以一些適用於vector的算法,如sort,unique都是可以用於數組的。
int nArr[5] = {4, 3, 2, 1, 5};
sort(nArr, nArr+_countfof(nArr));
vector<int> vInt(nArr, nArr+_countfof(nArr));
// 因爲vector內存是連續的,所以可以直接拷貝內存。
memcpy(nArr, &vInt[0], vInt.size()*sizeof(int));