C编程复合数据类型数组

C++中不仅有基本数据类型,还提供了更加灵活和丰富的复合数据类型。

在程序中为了处理方便,常常需要把具有相同类型的数据对象按有序的形式排列起来,形成“一组”数据,这就是“数组”(array)。

数组中的数据,在内存中是连续存放的,每个元素占据相同大小的空间,就像排好队一样。

1.数组的定义

数组的定义形式如下:

数据类型数组名[元素个数];

首先需要声明类型,数组中所有元素必须具有相同的数据类型;数组名是一个标识符;后面跟着中括号,里面定义了数组中元素的个数,也就是数组的“长度”;元素个数也是类型的一部分,所以必须是确定的;inta1[10];//定义一个数组a1,元素类型为int,个数为10

constintn=4;

doublea2[n];//元素个数可以是常量表达式

inti=5;

//inta3[i];//错误,元素个数不能为变量

需要注意,并没有通用的“数组”类型,所以上面的a1、a2的类型分别是“int数组”和“double数组”。这也是为什么我们把数组叫做“复合数据类型”。

2.数组的初始化

之前在讲到for循环时,提到过使用范围for循环可以遍历一个“序列”,用花括号括起来的一组数就是一个序列。所以在给数组赋值时,也可以使用这样的序列。

inta3[4]={1,2,3,4};

floata4[]={2.5,3.8,10.1};//正确,初始值说明了元素个数是3

shorta5[10]={3,6,9};//正确,指定了前三个元素,其余都为0

//longa6[2]={3,6,9};//错误,初始值太多

//inta6[4]=a3;//错误,不能用另一个数组对数组赋值

需要注意的是:

对数组做初始化,要使用花括号{}括起来的数值序列;如果做了初始化,数组定义时的元素个数可以省略,编译器可以根据初始化列表自动推断出来;初始值的个数,不能超过指定的元素个数;初始值的个数,如果小于元素个数,那么会用列表中的值初始化靠前的元素;剩余元素用默认值填充,整型的默认值就是0;如果没有做初始化,数组中元素的值都是未定义的;这一点和普通的局部变量一致;3.数组的访问

(1)访问数组元素

数组元素在内存中是连续存放的,它们排好了队之后就会有一个队伍中的编号,称为“索引”,也叫“下标”;通过下标就可以快速访问每个元素了,具体形式为:

数组名[元素下标]

这里也是用了中括号来表示元素下标位置,被称为“下标运算符”。比如a[2]就表示数组a中下标为2的元素,可以取它的值输出,也可以对它赋值。

inta[]={1,2,3,4,5,6,7,8};

couta[2]=a[2]endl;//a[2]=3

a[2]=36;

couta[2]=a[2]endl;//a[2]=36

需要注意的是:

数组的下标从0开始;因此a[2]访问的并不是数组a的第2个元素,而是第三个元素;一个长度为10的数组,下标范围是0~9,而不是1~10;合理的下标,不能小于0,也不能大于(数组长度-1);否则就会出现数组下标越界;(2)数组的大小

所有的变量,都会在内存中占据一定大小的空间;而数据类型就决定了它具体的大小。而对于数组这样的“复合类型”,由于每个元素类型相同,因此占据空间大小的计算遵循下面的简单公式:

数组所占空间=数据类型所占空间大小*元素个数

这样一来,即使定义的时候没有指定数组元素个数,现在也可以计算得出了:

//a是已定义的数组

couta所占空间大小:sizeof(a)endl;

cout每个元素所占空间大小:sizeof(a[0])endl;

//获取数组长度

intaSize=sizeof(a)/sizeof(a[0]);

cout数组a的元素个数:aSizeendl;

这里为了获取数组的长度,我们使用了sizeof运算符,它可以返回一个数据对象在内存中占用的大小(以字节为单位);数组总大小,除以每个数据元素的大小,就是元素个数。

(3)遍历数组

如果想要依次访问数组中所有的元素,就叫做“遍历数组”。我们当然可以用下标去挨个读取:

couta[0]=a[0]endl;

couta[1]=a[1]endl;

但这样显然太麻烦了。更好的方式是使用for循环:

//获取数组长度

intaSize=sizeof(a)/sizeof(a[0]);

for(inti=0;iaSize;i++)

{

couta[i]=a[i]endl;

}

循环条件如果写一个具体的数,很容易出现下标越界的情况;而如果知道了数组长度,直接让循环变量i小于它就可以了。

当然,这种写法还是稍显麻烦。C++11标准给我们提供了更简单的写法,就是之前介绍过的范围for循环:

for(intnum:a)

{

coutnumendl;

}

当然,这种情况下就无法获取元素对应的下标了。

4.多维数组

之前介绍的数组只是数据最简单的排列方式。如果数据对象排列成的不是“一队”,而是一个“方阵”,那显然就不能只用一个下标来表示了。我们可以对数组进行扩展,让它从“一维”变成“二维”甚至“多维”。

intarr[3][4];//二维数组,有三个元素,每个元素是一个长度为4的int数组

intarr2[2][5][10];//三维数组

C++中本质上没有“多维数组”这种东西,所谓的“多维数组”,其实就是“数组的数组”。

l二维数组intarr[3][4]表示:arr是一个有三个元素的数组,其中的每个元素都是一个int数组,包含4个元素;

l三维数组intarr2[2][5][10]表示:arr2是一个长度为2的数组,其中每个元素都是一个二维数组;这个二维数组有5个元素,每个元素都是一个长度为10的int数组;

一般最常见的就是二维数组。它有两个“维度”,第一个维度表示数组本身的长度,第二个表示每个元素的长度;一般分别把它们叫做“行”和“列”。

(1)多维数组的初始化

和普通的“一维”数组一样,多维数组初始化时,也可以用花括号括起来的一组数。使用嵌套的花括号可以让不同的维度更清晰:

数据类型数组名[行数][列数]={数据1,数据2,数据3,…};

数据类型数组名[行数][列数]={

{数据11,数据12,数据13,…},

{数据21,数据22,数据23,…},

};

需要注意:

内嵌的花括号不是必需的,因为数组中的元素在内存中连续存放,可以用一个花括号将所有数据括在一起;初始值的个数,可以小于数组定义的长度,其它元素初始化为0值;这一点对整个二维数组和每一行的一维数组都适用;如果省略嵌套的花括号,当初始值个数小于总元素个数时,会按照顺序依次填充(填满第一行,才填第二行);其它元素初始化为0值;多维数组的维度,可以省略第一个,由编译器自动推断;即二维数组可以省略行数,但不能省略列数。//嵌套的花括号的初始化

intia[3][4]={

{1,2,3,4},

{5,6,7,8},

{9,10,11,12}

};

//只有一层花括号的初始化

intia2[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

//部分初始化,其余补0

intia3[3][4]={

{1,2,3},

{5,6}

};

intia4[3][4]={1,2,3,4,5,6};

//省略行数,自动推断

intia5[][4]={1,2,3,4,5};

(2)访问数据

也可以用下标运算符来访问多维数组中的数据,数组的每一个维度,都应该有一个对应的下标。对于二维数组来说,就是需要指明“行号”“列号”,这相当于数据元素在二维矩阵中的坐标。

//访问ia的第二行、第三个数据

coutia[1][2]=ia[1][2]endl;

//修改ia的第一行、第二个数据

ia[0][1]=19;

同样需要注意,行号和列号都是从0开始、到(元素个数-1)结束。

(3)遍历数组

要想遍历数组,当然需要使用for循环,而且要扫描每一个维度。对于二维数组,我们需要对行和列分别进行扫描,这是一个双重for循环:

cout二维数组总大小:sizeof(ia)endl;

cout二维数组每行大小:sizeof(ia[0])endl;

cout二维数组每个元素大小:sizeof(ia[0][0])endl;

//二维数组行数

introwCnt=sizeof(ia)/sizeof(ia[0]);

//二维数组列数

intcolCnt=sizeof(ia[0])/sizeof(ia[0][0]);

for(inti=0;irowCnt;i++)

{

for(intj=0;jcolCnt;j++)

{

coutia[i][j]\t;

}

coutendl;

}

同样,这里利用了sizeof运算符:

行数=二维数组总大小/每行大小列数=每行大小/每个元素大小当然,也可以使用范围for循环:

for(autorow:ia)

{

for(autonum:row)

{

coutnum\t;

}

coutendl;

}

这里的外层循环使用了auto关键字,这也是C++11新引入的特性,它可以自动推断变量的类型;后面的是定义了一个“引用”。关于这部分内容,会在后面继续介绍。

5.数组的简单排序算法

数组排序指的是给定一个数组,要求把其中的元素按照从小到大(或从大到小)顺序排列。

这是一个非常经典的需求,有各种不同的算法可以实现。我们这里介绍两种最基本、最简单的排序算法。

(1)选择排序

选择排序是一种简单直观的排序算法。

它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后追加到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

选择排序可以使用双重for循环很容易地实现:

#includeiostream

usingnamespacestd;

intmain()

{

intarr[]={5,9,2,7,4,3,12,6,1,5,7};

intsize=sizeof(arr)/sizeof(arr[0]);

//选择排序

for(inti=0;isize;i++)

{

for(intj=i+1;jsize;j++)

{

if(arr[j]arr[i])

{

//如果arr[j]更小,就和arr[i]交换位置

inttemp=arr[i];

arr[i]=arr[j];

arr[j]=temp;

}

}

}

//输出

for(intnum:arr)

coutnum\t;

cin.get();

}

(2)冒泡排序

冒泡排序也是一种简单的排序算法。

它的基本原理是:重复地扫描要排序的数列,一次比较两个元素,如果它们的大小顺序错误,就把它们交换过来。这样,一次扫描结束,我们可以确保最大(小)的值被移动到序列末尾。这个算法的名字由来,就是因为越小的元素会经由交换,慢慢“浮”到数列的顶端。

冒泡排序的代码实现也非常简单,同样是使用双重for循环:

//冒泡排序

for(inti=0;isize;i++)

{

for(intj=0;jsize-i-1;j++)

{

if(arr[j]arr[j+1])

{

inttemp=arr[j+1];

arr[j+1]=arr[j];

arr[j]=temp;

}

}

}




转载请注明:http://www.aierlanlan.com/rzfs/6449.html