C++构造数据类型|数组
- 1. 数组类型
- 1.1 数组的概念
- 1.2 数组的特点
- 2. 一维数组定义与使用
- 2.1 一维数组的定义
- 2.2 一维数组初始化
- 2.3 一维数组的存储
- 2.4 应用示例
- 2.5 数组的地址
- 2.6 数组的使用注意
- 3. 二维数组的定义与使用
- 3.1 二维数组的定义
- 3.2 二维数组的初始化
- 3.2.1 嵌套初值表
- 3.2.2 线形初值表
- 3.3 二维数组的存取
- 3.4 二维数组的应用示例
1. 数组类型
1.1 数组的概念
数组是一组在内存中依次连续存放的、具有同一类型的数据变量所组成的集合体。其中的每个变量称为数组元素,它们属于同一种数据类型,数组元素用数组名与带方括号的数组下标一起标识。数组可以是一维的,也可以是多维的。 1
1.2 数组的特点
若干个同类型的数据元素,并且各个数据元素之间存在某种次序关系。这类数据有一个共同的特点:它们有若干个同类型的数据元素,并且各个数据元素之间存在某种次序关系。
2. 一维数组定义与使用
2.1 一维数组的定义
一维数组定义的一般形式为:
一维数组使用说明:
- 数组元素的类型可以是
void
型以外的任何一种基本数据类型,也可以是已经定义过的构造数据类型; - 数组名是用户自定义的标识符,用来表示数组的名称,代表数组元素在内存中的起始地址,是一个地址常量。
- 常量表达式必须是
unsigned int
类型的正整数。表示数组的大小或长度,也就是数组所包含数据元素的个数。 [ ]
是数组下标运算符,在数组定义时用来限定数组元素的个数。
注意: 数组属于构造数据类型,在使用之前必须先进行类型定义。- 数组元素的类型可以是void型以外的任何一种基本数据类型,也可以是已经定义过的构造数据类型;
例如:下面定义了2个不同类型的数组:
int a[5]; //定义了一个5个元素的整型数组aweekday b[10]; //定义了一个10个元素的枚举数组b,weekday为已定义的枚举型。
- 数据类型相同的多个数组可以在同一条语句中予以定义。例如:
int a1[10], a2[20]; //同时定义了两个整型数组
- 数据类型相同的简单变量和数组也可以在一个语句中定义。例如:
int x, a[20]; //同时定义了一个整型变量和一个整型数组
- 数组定义之后,系统会将从内存中为其分配一块连续的存储空间,从第1个数据元素开始依次存放各个数组元素。例如,定义的数组a其内存排列(分配)示意图如图所示。
int a[5]; //定义了一个5个元素的整型数组a
2.2 一维数组初始化
一维数组初始化是指在定义数组的同时给数组中的元素赋值。
其一般语法形式为:
其一般语法形式为:
{初值1,初值2,…, 初值n}
称为初值表,初值之间用逗号,分隔, 所有初值用{ }
括起来。- 初值可以是一个变量表达式,初值与数组元素的对应关系是:初值i给数组第i个元素;所以,初值个数n不能超过数组的大小。
- 若初值表中初值个数(项数)小于数组的大小,则未指定值的数组元素被赋值为0;但初值表中项数不能为0。例如:
weekday b[10]={MON,WED,FRI};
- 当对全部数组元素赋初值时,可以省略数组的大小,此时数组的实际大小就是初值列表中初值的个数。例如:
char str[ ] = {'a', 'b', 'c', 'd', 'e' }; //数组str的实际大小为5。
- 在函数中定义数组时,如果没有给出初值表,数组不被初始化,其数组元素的值为随机值;在函数外定义数组如果没有初始化,其数组元素的值为0。
- 数组初值表的可以用一个逗号结尾,其效果与没有逗号一样。
2.3 一维数组的存储
对一维数组实施的存取操作有两类:存取数组元素与读取数组元素的地址。数组元素是通过数组名及下标来标识的,这种带下标的数组元素也称为下标变量,下标变量可以象简单变量一样参与各种运算。
存取一维数组元素的一般语法形式为:
说明:
- 下标表达式可以是变量表达式,用来标识数组元素;不同于数组定义时用来确定数组长度的常量表达式。
- 当定义了一个长度为n的一维数组a,C++规定数组的下标从0开始,依次为0、1、2、3、…、n-1。对应的数组元素分别是a[0]、a[1]、…、a[n-1],因此下标表达式的值要在[0,n-1]范围内。
例如:
a[1+2]=100; // 将数组a的第4个元素赋值100
2.4 应用示例
【例1】学生成绩排序。
分析:学生成绩由键盘输入,当输入一个负数时,输入完毕。
采用直观的“选择排序法”进行排序,基本步骤如下:
① 将a[0]
依次与a[1]~a[n-1]
比较,选出大者与a[0]
交换;最后a[0]
为a[0]~a[n-1]
中最大者;
② 将a[1]
依次与a[2]~a[n-1]
比较,选出大者与a[1]
交换;最后a[1]
为a[1]~a[n-1]
中最大者;
③ 同理,从i=2
到i=n-1
, 将a[i]
依次与a[i+1]~a[n-1]
比较,选出较大者存于a[i]
中。
/******************************************
* 功 能:数组应用--选择排序 *
******************************************/#include<iostream>using namespace std;int main(){ const int MaxN=5;int n,a[MaxN],i,j;for (n=0;n<MaxN;n++){cin>>a[n]; //输入数组元素if(a[n]<0)break;}for(i=0;i<n-1;i++)for(j=i+1;j<n;j++) //从带排序序列中选择一个最大的数组元素if(a[i]<a[j]){int t;t=a[i]; //交换数组元素a[i]=a[j];a[j]=t;}//cout<<"排序后"<<endl;for(i=0;i<n;i++)cout<<a[i]<<"\t"; //显示排序结果return 0;}
2.5 数组的地址
数组元素的地址通过数组名来读取,其格式如下:
由于其地址不是实际的地址值,称这个地址表达式为符号地址表达式。例如:
一维数组元素a[5]
的符号地址表达式为a+5
。
若a
是一个int
型数组,数组的符号地址表达式a+n
所表达的地址是第n+1
个元素a[n]
的地址,代表的实际地址值为:a+n*sizeof(int)
而不是a+n
。
2.6 数组的使用注意
-
在使用数组时最常犯的错误是数组元素越界,包括上标越界和下标越界。上标越界是指数组元素的访问地址值超过了数组的起始地址;下标越界是指数组元素的访问地址越过了数组中最后一个数组元素的地址。对于这种错误,编译器无法知道,往往在运行时出错。因此在程序设计时应格外注意。
-
数组名是一个地址常量,不能作为左值(赋值的目标)。因此,不能将一个数组
整体拷贝给另外一个数组。
例如:
int a[5],c[5],i;a=c; //错误!
正确的方法是将对应的元素进行拷贝,见下列程序段:
for(i=0;i<5;i++)a[i]=c[i]; //将数组c中元素的值拷贝到数组c的对应元素中
- 在函数中,可以将一个一维数组作为函数的形式参数,用来接受一个一维数组传递过来的地址。
3. 二维数组的定义与使用
3.1 二维数组的定义
二维数组的定义的一般形式为:
其中:
- 常量表达式1为第1维的元素的个数,常量表达式2为第2维元素的个数。
- 二维数组
a[m][n]
是以长度为n的一维数组为元素的数组,因此,等价于如下定义方式:
例如:
int M[2][3];
定义了一个整型二维数组M,数组M也可以用下列方式定义:
typedef int M1[3]; // 定义了一个一维整型数组M1;
M1 M[2]; // 以M1为类型定义数组M
如果一维数组描述排列成一行的数据,那么,二维数组则描述若干行这样的数据。因此,二维数组可以看作是数学上的一个矩阵。第1维元素个数为矩阵的列数,第2维元素个数为矩阵的行数。
二维数组的定义格式可以写成:
定义一个二维数组后,系统为它分配一块连续的内存空间。
二维数组a[m][n]占内存空间的计算公式为:
既然一个二维数组是由若干个一维数组排列构成,二维数组在内存中的排列顺序为:先顺序排列每个一维元素,构成一维数组;再将各个一维数组顺序排列,构成二维数组。
int M[2][3]
的排列顺序为:先将3个int元素排列组成2个一维数组M[0], M[1]
。
M[0]:M[0][0],M[0][1],M[0][2]M[1]:M[1][0],M[1][1],M[1][2]
再将2个一维数组排成一个二维数组。
M: M[0], M[1]
数组M在内存中的排列图如图所示。
3.2 二维数组的初始化
二维数组的初始化 :
其中初值表具有两种形式:嵌套的初值表,线性初值表。
3.2.1 嵌套初值表
以二维数组M[m][n]为例,嵌套初值表的格式为:
嵌套初值表由一维初值表嵌套构成,各层构成规则与一维数组的初值表相同。
例如:
int M[3][4]={{1,2,3,4},{3,4,5,6},{5,6,7,8}}; //M数组元素被全部初始化 int a[2][3]={{1},{0,0,1}}; //初始化了部分数组元素int b[][3]={{1,2,3},}; //初始化了全部数组元素int d[][3]={{1,3,5},{5,7,9}}; //初始化了全部数组元素,省略了高维元素个数
3.2.2 线形初值表
线形初值表与一维数组的初值表相同,初值表的项数不超过各维元素个数的乘积(总元素个数)。
数组元素按内存排列顺序依次从初值表中取值,下列各数组使用了线形初值表,结果与使用嵌套初值表相同。
例如:
int M[3][4]={1,2,3,4,3,4,5,6,5,6,7,8}; //M数组元素被全部初始化
int a[2][3]={1,0,0,0,1,1}; //初始化了全部数组元素, 一部分元素未给初值
int b[ ][3]={1,0,0,0,0,0}; //初始化了全部数组元素, 省略了高维元素个数
当使用线形初值表而省略高维元素个数时,高维元素个数为:向上取整数(线形初值表项数/低维元素个数)
例如:
int b[ ][3]={1,0,0,0};//高维元素个数为2
3.3 二维数组的存取
存取维数组元素的格式为:
说明:
- 行下标表达式与列下标表达式的值同样从0开始,a[i][j]表示数组的第i+1行、第j+1列的元素。由于数组元素是变量,可以对其进行各种各种操作。
- 数组元素如果定义数组a[m][n], 即数组第1维大小为n, 第2维大小为m。a[i][j]的排列位置与在内存中的地址计算公式如下:
例如:
a, a[0]: 为数组a的起始地址, 即a[0][0]的地址; a[i]+j: 为数组的第i+1行的第j+1元素的地址,即a[i][j]的地址;
3.4 二维数组的应用示例
/********************************************************************
* 功 能:求学生多门功课的总分,并求所有学生各门功课的平均分 *
*********************************************************************/#include<iostream>using namespace std;int main(){const int MaxN=100,CourseN=5;int n,score[MaxN][CourseN+1]={0};float aver[CourseN+1]={0};for(n=0;n<MaxN;n++) //输入学生成绩{for(int j=0;j<CourseN;j++)cin>>score[n][j];if(score[n][0]<0) break; //输入-1,结束输入}for(int i=0;i<n;i++) //计算每个学生的总分for(int j=0;j<CourseN;j++)score[i][CourseN]=score[i][CourseN]+score[i][j];for(int j=0;j<CourseN+1;j++) //计算每门课程的平均分{for(int i=0;i<n;i++)aver[j]=aver[j]+score[i][j];aver[j]=aver[j]/n;}for(i=0;i<n;i++) //输出每个人的成绩与总分{for(int j=0;j<CourseN+1;j++)cout<<score[i][j]<<"\t";cout<<endl;}cout<<"--------------------------------------"<<endl;for(i=0;i<CourseN+1;i++) //输出每门功课的平均分cout<<aver[i]<<"\t";cout<<endl;return 0;}
本教程仅供教学使用,参考教材 :《C++语言程序设计教程》,杨进才、沈显君编著,清华大学出版社,2022年1月第4版 ↩︎