C++數組概述

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

  • 異同
    1. 相同點,數組與vector的內存都是連續的。
    2. 不同點,數組是固定大小,而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));
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章