在c++中,一個變量或數組變量定義完成后,其值均為系統預設,不一定是我們想要的。一般情況下,全局變量或數組系統會自動初始化(整數一般為0,布爾型為false,字符型為\0),而局部變量則為隨機。特別是數組變量,我們在使用中一定義可能就是很大數量的變量,系統預設的可能非我們想要的,那就存在數組變量的統一初始化了。如何初始化數組變量?
一、在數組定義時直接賦值
例1:int a[5]={1,2,3,4,5};這樣數組的每一個值都確定了,a[0]=1,a[1]=2,a[2]=3,a[3]=4,a[4]=5。
當然這種方法賦值很明確,但也很麻煩,特別是數組但很大時不太實用。如果給出值的個數超過定義個數,有的系統會報錯,有的系統則不會,但多出的值將會被忽略。例如int a[5]={1,2,3,4,5,6};如果不報錯則等效於int a[5]={1,2,3,4,5};,但一般會有警告。若末尾多一個逗號,一般不會報錯,好個逗號會被忽略。
例2:在賦值時我們也可以采用省略形式。例1中寫法也可以省略為int a[]={1,2,3,4,5};
這種寫法沒指定元素個數,那系統將根據我們提供的值的個數來確定定義的元素個數。如上例中就定義了5個元素,並完成賦值。同上,如果最后有一個逗號,一般會被忽略,不會計數。例如int a[]={1,2,3,4,5,};其作用跟int a[]={1,2,3,4,5};一樣。但若中間多逗號,例如int a[]={1,2,,3,4,5};則會報錯。
例3:我們還可以采用部分賦值法。如int a[10]={1,2,3};
我們定義了10個元素,但我們只給了三個值,這樣得到的結果是a[0]=1,a[1]=2,a[3]=3,其余元素的值全為0。
當然,我們也可以有一個極限寫法int a[10]={};一個值沒指定,也可以理解為指定了0個元素的值,其余元素的值全為0,即是全部元素值為0。
其他類型數組省略部分數據的值請參照全局變量預設。
例4:二維數組的可以看作多個一維數組,故可采用逐維賦值法。如int a[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,20,30}},其結果應該不難理解,
a[0][0]=1,a[0][1]=2,a[0][2]=3,a[1][0]=4,a[1][1]=5,a[1][2]=6,a[2][0]=7,a[2][1]=8,a[2][2]=9,a[3][0]=10,a[3][1]=20,a[3][2]=30。
例5:二維數組的逐維賦值法也可以采用省略形式,如int a[4][3]={{1},{2,},{3,4},{9,10,11}},其結果跟int a[4][3]={{1,0,0},{2,0,0},{3,4,0},{9,10,11}}效果一樣。
例6:二維數組也可以采用一維賦值相同的方法,二維數組的數據存儲一般采用行優先原則,如例4中各元素在內存中會依次存放數值1-10,20,30。根據這一規律,我們也可以定義為int a[4][3]={1,2,3,4,5,6,7,8,9,10,20,30},其效果跟例4一樣。當然,這個也可以采用省略形式,如果提供的數值個數不夠,后面的自動補0。如果提供的數值個數超出定義的個數,將會報錯。(這時所說定義個數指兩個維度乘積,如a[4][3]就定義了12個數)
例7:二維數組的第一個維度有時也可以省略,如int a[][3]={1,2,3,4,5,6,7,8,9,10,20,30},其效果跟例4一樣,當然如果所提供個數不是第二維度個數的整數倍,則系統會自動補0,如int a[][3]={1,2,3,4,5,6,7,8,9,10,20}將會等效於int a[4][3]={1,2,3,4,5,6,7,8,9,10,20,0}。注意,第二個維度不可省略,如定義為int a[4][]={1,2,3,4,5,6,7,8,9,10,20,30}就會報錯。(二維數組采用行優先原則,每一行元素個數不確定,就不能確定何時進入第二行)
二、利用全局變量自動初始化
在c++中,我們的數組定義大多在全局,這樣,數組會自動初始化,而且可用空間更大(局部定義數組范圍太大,容易爆棧--這一說法我也沒找到官方說明,在是其他博文中看到,如有不妥請大家指正)。
三、用fill函數初始化(需加頭文件<algorithm>,我用的IDE是DEV,不加頭文件也可以運行,其他IDE或評測系統未測試)
基本用法:fill(開始地址,結束地址,值);
這里的開始地址和結束地址一般用數組名代表首地址,數組名+偏移量來表示結束地址。
例1:int a[10]; fill(a,a+10,1);這樣就把數據中10個元素的值均賦值為1。
例2:int a[10]; fill(a+1,a+9,2);這樣就把數組中第2到9個元素的值賦值為2,其他元素的值未改變。(如果定義部分在全局,那其他元素的值為0,如果在局部定義的,那其他元素的值還是隨機的)
四、用memset函數(須加頭文件<cstring>)
memset函數是按字節賦值,基本用法:memset(開始地址,每字節的值,需賦值的字節數);
以下示例是數組均定義為int a[10];
例1:memset(a,0,40);作用是把a數組的所有10個元素賦值為0。
為什么是40而不是10呢?這個函數是按字節賦值,每個int的變量占4字節,10個int變量就占40字節。這種對全部變量賦值的寫法一般可換成memset(變量名,每字節的值,sizeof(變量名));如上例可改為memset(a,0,sizeof(a));
例2:memset(a,1,sizeof(a));作用是把數組范圍內每一個字節(不是變量)的值賦值為1。那個變量實際的值為多少呢?
由於每個int變量占4字節,每個字節的值為1,換成二進制來看,每個變量變量的值實際應為00000001 00000001 00000001 00000001(為了方便大家看,我在每兩個字節中間加了空格),換成10進制為16843009。即把a數組中每個值都賦值為16843009。
例3:如果想給變量賦更大的值可以用memset(a,0x7f,sizeof(a));即每個變量的值換成二進制為01111111 01111111 01111111 01111111,這個值幾乎接近int類型的上限(2^31-1),這樣的兩值相加就將會溢出。如果希望值很大還有接受一次加法,可考慮memset(a,0x3f,sizeof(a));這樣每個變量的值大約為1e9,略低於最大int值的一半。
例4:memset(a,-1,sizeof(a));作用是將每個變量的值均賦值為-1。對於一字節有符號的數值來說,最高位為1代表負數,后面的值用反碼表示,那一字節的-1就用11111111表示,四字節的-1則表示成11111111 11111111 11111111 1111111,故實際感覺就是按位填充0和-1得到的int值和按值填充0和-1實際效果一樣。
例5:memset(a+2,1,20);作用是把數組中第3到7個值賦值為16843009,其他值未改變。這里的20是字節數,int類型一個變量占4個字節,即20字節實際占用5個變量范圍,a[3]到a[7]正好5個變量。
注意memset與fill兩個函數的不同!
五、循環賦值(手動賦值)
對於其他需求情況下,還可以利用循環賦值初始化。
例1:for(int i=0;i<10;i++)a[i]=0x7fffffff;可把數組a[0…9]全賦值為2^31-1;(這里的0x7fffffff是16進制表示數)。
循環賦值是一種較為靈活的賦值方法,可根據需要進行,也可以對各個變量賦不同的值。
例2:for(int i=0;i<10;i++)a[i]=i;其效果等同於直接定義賦初值int a[]={0,1,2,3,4,5,6,7,8,9};
特別提醒:
1、數組名+n方式取得的地址不是按字節計算地址偏移量,而是按變量實際占位偏移位置。
例如:int a[10]定義數組,那么a+2則是數組首地址向后偏移2個int位,即8字節,若用long long int a[10]定義數組,a+2則是數組首地址向后偏移16字節。
2、一般來說,memset的效率比fill高。
3、數組賦值要注意別讓下標越界,否則是導致不可預知的錯誤。