在c++中,一个变量或数组变量定义完成后,其值均为系统预设,不一定是我们想要的。一般情况下,全局变量或数组系统会自动初始化(整数一般为0,布尔型为false,字符型为 ),而局部变量则为随机。特别是数组变量,我们在使用中一定义可能就是很大数量的变量,系统预设的可能非我们想要的,那就存在数组变量的统一初始化了。如何初始化数组变量?
一、在数组定义时直接赋值
例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、数组赋值要注意别让下标越界,否则是导致不可预知的错误。