督促讀書,總結精華,提煉筆記,拋磚引玉,有不合適的地方,歡迎留言指正。
c和c++的數組和指針都屬於低級的復合數據類型,比如c++的數組,類似vector容器,指針類似迭代器。低級的數據類型優勢是速度快。但是容易出錯,不好調試。現代c++程序,應該避免使用。
內置數據類型—數組,不方便存儲變長數據,定義之后長度固定(靜態數組),數組類似容器,比如,無法事先知道一個給定數組的長度,也沒有類似size函數來求數組長度,也沒有push_back()函數來添加元素,如果要更改數組長度,程序員只能重新建立數組,把舊的復制到新的。
記住現代c++程序,應該盡量是vector容器來替代數組,來存取同一類型的數據元素,只有當要求速度的前提下,如果使用容器不達標,那么再使用數組。
問題1、array由一系列的類型相同的元素構成,數組聲明包括數組元素個數和類型,數組最好定義之后就初始化。
數組的聲明
//[]方括號表示聲明的是數組,里面的數字表明了數組包含的元素數目 int states[50];//聲明50個整數的數組 double code[365];//聲明365個浮點數的數組 char chr[20];//聲明20個字符的數組
訪問數組內容可以用下標表示單個元素,下標數字也叫索引(index),從0開始計算。
數組的初始化
//用花括號括起來,元素用逗號隔開 int pow[8] = {1, 2, 3, 4, 5, 6, 7, 8};//只有標准c,c++支持此初始化語法 //pow[0]首元素賦值為1,以此類推
注意:數組聲明的時候最好是初始化,雖然不會報錯,但是和普通變量一樣,使用沒有初始化的數組,里面元素的值不定,出現垃圾值。
數組初始化列表和大小不一致的情況
初始化列表里的元素個數和數組大小不一致,當初始化元素數目少於數組大小,多余的元素自動初始化為0。如果沒有初始化數組,那么和普通變量一樣,存取的內存原來就有的垃圾值。初始化了,只不過部分初始化,那么編譯器會自動初始化余下的元素為0。初始化了,但是初始化列表元素大於數組大小,那么編譯出報錯。
//初始化沒有完全,編譯器自動后面給初始化為0 double d[4] = {1};//不過vs2010里編譯運行,全都是0 //error C2078: 初始值設定項太多 double d[4] = {1, 2, 3, 4, 5, 6};
數組初始化小技巧
省略填寫數組大小,讓編譯器自動的去判斷數組的實際大小和初始化列表里的項目
//空的方括號告訴編譯器去初始化列表里判斷數組實際大小 char chr[] = {'a', 'b', ' ', '4'}; //這里需要一個技巧,人工判斷數組大小容易出錯,使用sizeof運算符計算 for (int i = 0; i < sizeof(chr) / sizeof(chr[0]); i++) { cout << "i + 1 = " << chr[i] << endl; }

注意技巧:sizeof(數組名)求的是數組總共多大(字節單位),sizeof(數組【0】)求的是數組中一個元素的大小(字節單位),兩者除法,就是數組的實際大小(元素個數)。
數組使用小技巧(常量大小)
const int NUM = 4;//常量代表數組大小,推薦的技巧 int days[NUM] = {1, 2, 3, 4};//良好的編程風格,如果以后想修改數組大小,只需要修改開頭的常量即可 for (int index = 0; index < NUM; index++) { cout << days[index] << endl; }
對數組指定元素初始化
屬於C99的新特性,可以對數組指定的元素直接初始化,如果對數組最后一個元素初始化,那么傳統語法必須順次初始化到最后一個元素前,才能對最后一個元素初始化。
//對最后一個元素初始化為1 float f[3] = {0, 0, 1};
而c99規定可以直接去初始化
//使用方括號【】,直接對數組某個元素初始化 int i[3] = {i[2] = 100};//ok!需要加 數組名【】 //int in[5] = {[4] = 10};//error C2059: 語法錯誤:“[”
對於一般的數組初始化,部分初始化之后,余下的自動初始化為0(這里vs2010編譯器不是這樣的,全部都是0 了),如果在指定的初始化元素后還有別的初始化值,那么這些數值自動對數組后續元素進行初始化,並且指定初始化元素的數值在第幾個元素處,那么也會同樣初始化這個元素。
比如in【0】=11在第5(0-5)個元素位置,那么同時打印第5個元素=11。說明初始化指定元素的同時,也用這個數值初始化本位置的元素了。
如果多次對數組某個元素初始化,則最后一次為准。
int in[7] = {1, 2, in[2] = 10, 3, 4, in[0] = 11}; //首元素i0=11,i5=11 int i; for (i = 0; i < 7; i++) { cout << "i" << i << " = " << in[i] << endl; }

只讀數組
如果只需要對數組讀取,而不進行修改,那么推薦關鍵字const
const int days[NUM] = {1, 2, 3, 4};//數組中每個元素都當作常量處理,和普通變量一樣,const數組也需要聲明的時候初始化
數組的賦值
使用數組下標(索引)為數組元素賦值,c和c++不支持整體賦值的初始化,或者就是單純的賦值,也不支持用花括號括起來的列表進行賦值(初始化除外)
double d[SIZE] = {1, 2, 3};//ok這是可以的,列表進行初始化 int i[SIZE]; for (int count = 0; count < SIZE; count++) { i[count] = 2 * count;//ok,使用循環和數組下標給數組元素賦偶數值 } //i = d;//error,c不支持數組整體賦值 //i[SIZE] = d[SIZE];//error //d[SIZE] = {11, 22, 33};//不起作用,這種形式只有初始化可以使用,賦值必須使用索引
數組的邊界問題
千萬不要越界(類似數據類型的越界),數組索引不能越界,因為編譯器不會檢測這種錯誤。編譯器不會檢測索引的合法性,如果出現非法的索引,那么結果未知,有時候會中斷,但是也有時候可以執行,但是結果很奇怪(編譯器不同而不同),編譯器不檢測數組邊界,是出於信任程序員,可以節省時間和效率。
注意:記住,數組計數原則上都從0開始,並且數組大小用符號常量代替。減少錯誤的發生。
再看數組大小的指定
前面可以用整型常量(unsigned)或者字符常量來指定大小,C99之前就是這兩種方法。
const int const_m = 10;//在c語言(不同於c++)里,const值不被看作是常量,在c++里,這樣的定義的變量,也就是const常量,可以去做數組的維數。 int n = 100;//定義了變量n double d1[10];// ok double d2[5 * 2 + 1];//ok double d3[];//error,沒有初始化,也沒有大小指定 double d4[sizeof(int)];//ok,sizeof表達式在c里被認為返回一個整數常量 double d5[-10];//error C2118: 負下標 double d6[0];//error C2466: 不能分配常量大小為 0 的數組 double d7[3.14];// error C2058: 常量表達式不是整型 double d8[(int)3.14];//ok double d9[const_m];// error C2057: 應輸入常量表達式,“d9”未知的大小,不能分配常量大小為 0 的數組 double d10[n];//error C2057: 應輸入常量表達式,“d9”未知的大小,不能分配常量大小為 0 的數組
c99之后,后兩種方式可以了,並且創建了一種新數組VLA(variable length array)變長數組,VLA。目的是為了讓c更適合做數值計算。
問題2、下列語法是不合法的
int ia[get_size()];
非法,get_size()是函數調用,不是常量表達式,不能用於定義數組的維數(維長度)。記住,必須是程序編譯期間就得確定數組的大小,運行期間的不行。
問題3、注意下列數組的初始值
//ia 為在函數體外定義的內置數組,也就是全局變量,各元素初始化為0 int ia[10]; //sa為元素類型為string 的數組,自動調用string 類的默認構造函數將各元素初始化為空字符串 string sa[10]; int main(void) { //sa2 為元素類型為string 的數組,自動調用string 類的默認構造函數將各元素初始化為空字符串 string sa2[10]; //ia2 為在函數體內定義的內置數組,各元素未初始化,其值不確定 int ia2[10]; system("pause"); return 0; }
問題4、不要把數組和vector容器混淆
//vector 對象不能用這種方式進行初始化。 //vector<int> ivec = {0, 1, 1, 2, 3, 5, 8};
int ia3[] = ivec;//錯誤。不能用vector 對象來初始化數組。
定義數組時可使用初始化列表來初始化數組的部分或全部元素。如果是初始化全部元素,可以省略定義數組時方括號中給出的數組維數值。
如果指定了數組維數,則初始化列表提供的元素個數不能超過維數值。如果數組維數大於列出的元素初值個數,則只初始化前面的數組元素,剩下的其他元素,若是內置類型則初始化為0,若是類類型則調用該類的默認構造函數進行初始化。
字符數組既可以用一組由花括號括起來、逗號隔開的字符字面值進行初始化,也可以用一個字符串字面值進行初始化。
問題5、列出使用數組而不是vector 的缺點
與vector 類型相比,數組具有如下缺點:數組的長度是固定的(C99之前),而且數組不提供獲取其容量大小的size 操作,也不提供自動添加元素的push_back 操作。因此,程序員無法在程序運行時知道一個給定數組的長度,而且如果需要更改數組的長度,程序員只能創建一個更大的新數組,然后把原數組的所有元素復制到新數組的存儲空間中去。與使用vector 類型的程序相比,使用內置數組的程序更容易出錯且難以調試。
問題6、注意數組下標越界問題
類似vector容器,string類型,別無他法,一定自習檢查。常見的“緩沖區溢出錯誤”,就是在編寫代碼的時候,引用了越界的下標,沒有檢查下標的范圍,導致出錯!
歡迎關注
dashuai的博客是終身學習踐行者,大廠程序員,且專注於工作經驗、學習筆記的分享和日常吐槽,包括但不限於互聯網行業,附帶分享一些PDF電子書,資料,幫忙內推,歡迎拍磚!

