数组

第5章

本章要点

.数组的概念。
.一维数组、二维数组的声明及初始化。
.数组作为函数的参数。
.字符串与数组的关系。
.数组的应用(排序、查找、统计、字符处理和数列处理等)。
在程序中,经常需要保存大量具有相同类型的数据,如在程序中保存10 个学生的考
试成绩,并对成绩进行排序、统计等操作。最直接的想法是定义10 个变量n1,n2,n3,…,n10 
用于存放考试成绩,且不说如何对10 个变量进行排序,就是为这10 个变量赋初值就比较麻
烦。这只是10 个数据,如果是1000 个或更多的数据,对这些数据操作的复杂程度可想而
知。为解决上述问题,C+
+ 
提供了一个很好的复合类型———数组。数组与循环控制结构
配合使用,可以很方便地解决对大量数据赋值、排序、统计等操作问题。

5.数组的基本概念
1 

数组是具有相同类型的一组数据的集合,且占用连续的内存单元用于存储信息。组成
数组的对象称为数组元素,可以通过指定数组元素在数组中的位置编号来访问数组中的
元素。

例如,定义数组score[] 用于存放10 个学生的成绩: 

intscore10=78669372849067818695 

表5-1列出了整型数组score[] 的各数组元素及其值。

表5-
1 
数组score[] 的各数组元素及其值


数组元素数组元素的值

score[0] 78 
score[1] 66 
score[2] 93 
score[3] 72 
score[4] 84 

数组元素数组元素的值

score[5] 90 
score[6] 67 
score[7] 81 
score[8] 86 
score[9] 95 

score数组包含10 个元素,可以用数组名加上方括号“[]”中该元素的位置编号访问这


C+
+ 
程序设计基础(第2版) 

些元素。例如,e[] 数组中的第1个元素为se[0], 第2个元素为se[1],……, 第

scorcorcor
10 个元素为se[9]。由此可见,e[] 数组中的第i个元素为se[1]
。


corscorcori
在实际应用中,数组分为简单的一维数组和较为复杂的多维数组
。


114
5.一维数组
2 

5.1 
一维数组的声明
2.
数组在使用前必须先声明。声明一维数组的形式如下: 


类型标识符
数组名
数组长度
其中,类型标识符决定数组中每一个数组元素可存储数据的类型,一个数组中,所有数组元

素的类型都是相同的;数组名必须遵循C+
+ 
语言对标识符的要求,其命名规则与其他变量名

相同;数组长度是个常量表达式,它规定了数组的大小,即所声明的数组由多少个数据类型

相同的存储空间组成。

数组的声明为数组分配了存储空间,数组中每个元素在内存中是依次排列的。例如: 

intscore10 

定义了名称为score的一维数组,该数组有10 个元素,且每一个数组元素都是int类型的, 
即每一个数组元素占4字节,所以该数组在内存中一共占4×10=40 字节,且这些存储空间
是连续的。

在声明数组时,要注意数组的长度只能由常量表达式来决定,不能有变量出现,即数组

的长度必须是确定的。如果有变量出现,在编译时编译器会给出错误信息。例如: 

intconstN=10
intnm=
3
intaN 合法N为常变
量
doublebn cm*12 不合法n和m为变
量


5.2 
一维数组的初始化
2.
变量可以在声明时赋初值,数组也可以在声明时给所有或部分数组元素赋初始值。声
明时给一维数组元素赋初始值有如下两种形式。

形式1: 


类型标识符


数组名


数组长度= 第0个元素值第1个元素值
… 
第n-1个元素值


形式2: 


类型标识符


数组名
= 第0个元素值第1个元素值
… 
第n-1个元素值
第一种形式将声明一个长度为“数组长度”的数组,然后将花括号内的值依次赋予数组
的各个元素。花括号内只能是常量表达式。如果花括号中的常量表达式的个数少于数组长
度,则剩余的数组元素就不被赋予初始值,都被“清零”;如果花括号中的常量表达式的个数
大于数组长度,则编译器会给出错误信息。


第二种形式将声明一个长度为n的数组,并将花括号内的n个值依次赋给数组的各个
元素。注意,此时数组的长度未给定,而是由花括号内的数据个数决定的。
特别提示:以下形式是不允许的。


类型标识符
数组名
= 第0个元素值第2个元素值.. 第n-1个元素值
例如: 

inta =123 合法默认数组长度为3a0=1a1=2a2=3 
intb5=123 合法b0=1b1=2b2=3b3=b4=0 
intc =1345 不合法1和3之间不能有"空" 
intd6=1234567 不合法初值个数7 


数组长度6 
5.3 
访问一维数组的元素
2.
带下标的数组名就是下标变量,也称为数组元素。对数组的操作一般都是通过访问数
组元素来实现的。访问一维数组元素的形式如下: 


数组名
下标
下标就是数组元素的索引值,即数组元素在数组中的位置编号,它代表了要访问的数组
元素在数组中与第1个数组元素(下标值为0)的相对位置。例如,数组a[] 中第1个数组元
素a[0]的下标为0,因为就是它本身,所以它与第1个数组元素a[0]的相对位置为0;第
2个数组元素a[1]的下标为1,代表它与第1个数组元素a[0]的相对位置为1,即a[1]是
a[0]的下一个元素;第3个数组元素a[2]的下标为2,表示它与第1个数组元素a[0]的相
对位置为2,以此类推。

下标值的允许范围是0~N-1(N为数组的长度)。在声明数组时,数组的长度只能是
常量,而在访问数组元素时,下标可以是任意的整型表达式,只要表达式的取值范围在
0~N-1即可。

在实际的程序设计中,要特别注意下标值的溢出问题。C+
+ 
在编译时不对下标值的合
法性进行检查。换句话说,如果声明了一个长度为100 的数组,访问下标为0、下标为-1、
下标为120 的元素,在语法上都是正确的,这就要求程序员在编写程序时要格外小心。如果
访问数组中的元素时下标值在允许的范围以外,就等于企图侵入程序中(甚至是整个系统
中)其他模块或变量、数组等的存储空间,尽管编译时不会有任何问题,但在程序运行时操作
系统一般会给出保护模式错误警告。

数组元素可以当成普通的变量使用,也就是说在程序中所有变量可以出现的地方都可
以用数组元素替代,当然数组元素也可用于赋值语句的左边。

例如,声明一个长度为20 的整型数组,并将数组中的各个元素按顺序赋予从50 到70 
以1递增的数,即赋予数组的第0个元素的值为50,赋予数组的第1个元素的值为51,以此
类推。为了能访问到数组中的所有元素,需要用一个简单的for循环语句,循环控制变量从
0开始,以1为增量,一直递增到19,而循环控制变量正好可以作为访问数组元素时的下标。
要按顺序给数组元素赋予从50~70 的值,只要让每个数组元素的值等于其下标值加上50 
(也就是将循环控制变量加上50)即可。相应的程序代码片段如下: 

115
第
章

数组


116
C+
+ 
程序设计基础(第2版) 

intnData20
forinti=0i 20i+
+
nDatai=i+50


【例5-1】假定一个班级有20 名学生,所有学生某门课程的考试成绩保存在一个一维
数组中。编写程序,找出该班学生该门课程考试的最高分,并计算平均分数和统计考试成绩
不及格的学生人数。

问题分析:这是一个典型的顺序查找统计问题。可以通过数组与循环的配合遍历20 
个学生的成绩,实现查找最高分和统计总分和不及格人数的目的。这里的查找最高分实际
上是在所有成绩中找到最大值,可以先假定第1个数组元素为最大值,之后通过循环结构将
每一个数组元素与当前的最大值进行比较,并记录最大值所在位置,最终查找到最高分。程
序代码如下: 

#includeiostream
#includeiomanip
usingnamespacestd
intmain



intnScore20=90884592765989936051 定义一维数组并赋初值
91658274923566786291 
intnSum=0nUnPassedCount=0 计数变量清零
输出数组

forinti=0i 20i+
+ 

ifi%10==0 每输出10个数据后换行
cout endl 
cout setw4 


nScorei 
顺序查找和统计
intmax=nScore0k 先假定第1个数组元素为最大值
fori=0i 20i+
+ 

ifmaxnScorei 找到最大值

max=nScorei
k=
i


nSum+=nScorei 求和
ifnScorei 60 统计不及格人数
nUnPassedCount+
+ 

输出查找和统计结果
cout "\\n考试最高分为" max "是第" k+1 "个" endl 
cout"平均分数为" floatnSum20 endl 为更精确显示结果将int型转换成float型
cout "不及格人数为" nUnPassedCount endl 
return0 

程序运行结果: 


1 17 
第5章
数 组 
考试最高分为:93 是第8 个
平均分数为:73.95 
不及格人数为:4 
程序中首先定义了一个长度为20的一维数组,并将20名学生的考试成绩赋值给一维
数组。接着的第1个for语句按每行10个数据的格式输出20个考试成绩,此功能是通过
选择语句判断如果循环变量i能被10整除则回车换行实现的。接着假定第1个数组元素
nScore[0]为最大值并赋值给变量max,第2个for语句控制循环20次,通过遍历每一个学
生的考试成绩,通过将数组元素nScore[i]与max进行比较,并用变量k记录最大值的位
置,最终查找出成绩最高分并存入变量max中,在此遍历学生考试成绩的同时,判断每一个
学生的考试成绩是否小于60,据此统计不及格人数。
【例5-2】 输入3个不同的整数,找出最大的数和中间的数,并输出结果。
问题分析:如果不使用数组,在3个数中找最大的数和中间的数是比较麻烦的。现在
将3个数赋值给一维数组,并与循环控制结构结合将数组中所有元素重新按照递增顺序排
序,这样在排序后的数组中就能很容易地找到最大的数和中间的数。程序代码如下: 
#include iostream 
usingnamespacestd 
constintN=3 
intmain 
inta N 
inti j t k 
cout "输入任意3个不同的数 " 
for i=0 i N i++ 循环输入N个值 并赋值给一维数组a 
cin a i 
for i=0 i N-1 i++ 或for i=0 i 2 i++ 
k=i 
for j=i+1 j N j++ 或for j=i+1 j 3 j++ 
if a j a k k=j 
if k =i 
t=a i 
a i =a k 
a k =t 
cout "按照递增排序后的数组为 " 
for i=0 i N i++ 
cout a i "\\t" 
cout "\\n3个数中最大值为 " a 2 endl 
cout "3个数中中间的值为 " a 1 endl 
return0 

C+
+ 
程序设计基础(第2版) 

程序运行结果: 

输入任意3个不同的数738 
按照递增排序后的数组为378 
3个数中最大值为8 
3个数中中间的值为7 

118
5.多维数组
3 

如果一个数组元素本身也是数组,就形成多维数组。一维数组的下标数只有一个,而多
维数组的下标数有多个,多维数组中最常用的是二维数组。

5.1 
二维数组的声明
3.
声明一个二维数组的形式为: 


类型标识符
数组名
第1维长度第2维长度
同一维数组一样,二维数组的数组名必须遵循C+
+ 
标识符的命名规则。数组第1维长
度和第2维长度都是常量表达式,常量表达式中同样不能有任何变量出现。二维数组通常
用于存放矩阵或二维表中的数据,因此在二维数组中,常称第1维为行,第2维为列。

例如,语句intnMatrix[3][4]将声明一个名为nMatrix且第1维长度为3、第2维长度
为4的二维数组,称为3行4列的二维数组,与二维表格之间的对应关系如表5-2所示。

表5-
2 
二维数组与二维表格之间的对应关系

行
列0 1 2 3 
0 
1 
2 
nMatrix[0][0]
nMatrix[1][0]
nMatrix[2][0] 
nMatrix[0][1]
nMatrix[1][1]
nMatrix[2][1] 
nMatrix[0][2]
nMatrix[1][2]
nMatrix[2][2] 
nMatrix[0][3]
nMatrix[1][3]
nMatrix[2][3] 

由表5-2可知,对于第1行,第1维的值都为0,且从左到右第2维的值由0增至3;在第
2行,第1维的值都为1,从左到右第2维的值重新由0增至3;在第3行,第1维的值都为
2,从左到右第2维的值再次由0增至3。因此,如果将二维数组名和第1维下标看作一个
整体当作一维数组名,则二维数组中每行的元素就相当于一个一维数组。例如,如果将
nMatrix[0]看作一个数组名,则第一行的4个元素就组成了一个长度为4的一维数组。那
么3行4列的二维数组可以看成由3个长度分别为4的一维数组所构成,这3个一维数组
名分别为nMatrix[0]、nMatrix[1]和nMatrix[2]。

不难算出,3行4列的二维数组中共有3×4=12 个整型元素,这12 个元素在内存中是
按顺序存放的,先从左到右存放第一行的4个元素,紧接着从第二行的第1个元素开始,从
左到右依次存放第二行的4个元素,最后存放第三行的4个元素。了解二维数组元素在内
存中的存储方式,对在程序中访问二维数组元素很有益处。


5.2 
二维数组的初始化
3.
同一维数组一样,二维数组也可以在声明时赋初始值,形式如下
。
形式1:



类型标识符
数组名
第1维长度第2维长度= 第0个第2维数据组
第1个第2维数据组
.. 
第n-1个第2维数据组

其中,n等于第1维长度
。
形式2:



类型标识符
数组名
第1维长度第2维长度= 第0个元素值
第1个元素值
.. 
第m-1个元素值
其中,m等于第1维长度乘第2维长度之积。

这两种形式中,如果花括号中给出的元素个数少于实际的元素个数,则剩余的数组元
素
将会自动赋值为0,也称“清零”;如果花括号中给出的元素个数大于实际的元素个数,则
编
译器会给出错误信息。例如
:


inta 3=1234560 合法a00=1a10=2.. 
intb 3= 1234560 不合法因为1之前不能有"空" 
intc 3=123460 不合法因为4和6之间不能有"空" 
intd22=12345 不合法初值个数大于数组的元素个数

3.访问二维数组的元素
5.3 
要访问二维数组中的元素,同样需要指定要访问的元素的下标。二维数组的元素有两
个下标,访问二维数组元素的形式为: 


数组名
第1维下标第2维下标
这里,下标的值也是从0开始,且不能超过该维的长度减1。下标可以是任意整型表达式, 
只要其值在该下标的有效范围内即可。

要访问二维数组中的某个元素,必须给出该元素所在的行和列。如nMatrix[2][1]代
表数组名为nMatrix的二维数组中位于第3行、第2列的元素。同一维数组一样,二维数组
的元素也可以当成变量进行赋值或参与各种表达式的计算。

【例5-3】生成如下格式的方阵,将其存入二维数组中。

(1)输出二维数组所有元素的值。
(2)求该方阵每行、每列及对角线(左上右下)之和
。
12345
109 8 7 
6
1112131415
数组

119
第
章


120
C+
+ 
程序设计基础(第2版) 

2019181716 
2122232425 
问题分析:二维数组的行和列同矩阵的行和列是对应的。因此,为了访问二维数组中

的所有元素,应使用双重循环,外层循环控制变量作为当前行,内层循环的循环控制变量作
为当前列。

这个方阵的规律在于:偶数行中的元素按升序排列,奇数行中的元素按降序排列,只要
按此规律逐行“处理”方阵中的元素,即可得此方阵。在显示二维数组时,为了得到理想的显
示效果,要对不同的元素指定不同的显示位置。另外,考虑除需要存放5×5 方阵的各元素,还
要存放各行和各列以及左上右下对角线之和,因此定义一个6×6 的方阵,最后一列数组元素
用于存放对应行之和,最后一行的数组元素用于存放对应列之和,最后一个数组元素则用于
存放左上右下对角线上各数之和。程序代码如下: 

#include 


iomanip
#includeiostream
usingnamespacestd
intmain
intnRow 控制行的变量
intnCol 控制列的变量
intnMatrix66=0 二维数组声明且数组元素被赋值为0 

生成5×5 方
阵
fornRow=0nRow5nRow+
+


fornCol=0nCol5nCol+
+ 

ifnRow%2==0 
nMatrixnRownCol=nRow*5+nCol+1 
else 
nMatrixnRow4-nCol=nRow*5+nCol+1 

输出方
阵
cout "生成方阵为\n"
fornRow=0nRow5nRow+
+


fornCol=0nCol5nCol+
+ 

cout nMatrixnRow nCol 
ifnMatrixnRow nCol 10 控制输出1位数与2位数时的不同间隔
cout setw3 " " 
else 
cout setw2 " " 

cout endl 每输出一行后换行

cout endl
计算5×5 方阵各行及左上右下对角线之
和
fornRow=0nRow5nRow+
+



fornCol=0nCol5nCol+
+ 

nMatrixnRow5+=nMatrixnRownCol 计算各行之和
nMatrix5 nRow+=nMatrixnColnRow 计算各列之和

nMatrix55+=nMatrixnRownRow 
cout"第" nRow+1 "行之和" nMatrixnRow 5 "\t\t" 
cout"第" nRow+1 "列之和" nMatrix5 nRow 


endl 
cout "\n左上右下对角线之和" nMatrix5 5 


endl
return0
程序运行结果: 

生成方阵为

12345
109 8 7 
6
1112131415
2019181716
2122232425


第1行之和15 第1列之和63
第2行之和40 第2列之和64
第3行之和65 第3列之和65
第4行之和90 第4列之和66
第5行之和115 第5列之和67


左上右下对角线之和65 

特别需要说明的是,语句

intnMatrix66=0 

与语句块

intnMatrix66
fornRow=0nRow6nRow+
+
fornCol=0nCol6nCol+
+
nMatrixnRownCol=
0


的作用相同,都是将数组元素“清零”。前者是在声明二维数组的同时,只将数组元素

nMatrix[0][0]赋值为0,剩余的数组元素将自动“清零”;后者是在二维数组声明后,通过循
环逐个将每一个数组元素赋值为0。

如果数组只声明不赋值,其数组元素不会自动“清零”,这时数组元素的值是不确定的, 
不能直接使用。如果将数组用static说明为静态的,则数组中所有元素将自动赋初值为0, 
无须再对数组进行“清零”的操作,即

staticintnMatrix66 

121
第
章

数组


C+
+ 
程序设计基础(第2版) 

可以替代以下代码: 

intnMatrix66 
fornRow=0nRow6nRow+
+ 
fornCol=0nCol6nCol+
+ 
nMatrixnRownCol=0 

122
5.数组作为函数参数
4 

C+
+ 
将数组名解释为该数组第一个元素的地址,并视数组名为指针。有关指针的概念
将在第7章介绍,这里只结合数组参数的传递过程,对数组名作为函数参数的编程方法进行
介绍。

5.1 
一维数组名作为参数
4.
在涉及函数调用的程序设计中,通常需要将数组中存放的所有数据传递给被调用函数。
最直接的想法是将该数组中的所有元素都作为参数,一个一个地传递给被调用函数。显然, 
随着数组元素的增多,函数的参数阵容将非常庞大,所以这种方法基本上是不可行的。在实
际的程序设计中,通常采用只将数组名(即数组中第一个数组元素的地址)作为实参传递给
被调用函数的方法,实现将整个数组传递给被调用函数的目的。例如,在主函数main() 中声
明了如下数组: 

intnScore20 

如果要将该数组中的所有数据传递给另一个函数func(), 则在函数main() 中,可用下
列形式的函数调用语句: 

funcnScore20 

这里,数组名nScore是数组元素nScore[0]的内存地址,20 是整个数组的元素个数,即数组

的长度。

一维数组作为参数时,函数的声明主要有以下两种形式。

形式1: 


类型标识符
函数名
类型标识符数组名int长度
形式2: 


类型标识符
函数名
类型标识符数组名长度
第一种形式适用于处理不同长度的数组,数组的实际长度通过另一个参数传递给函数; 
第二种形式只可用于传递长度固定的数组。不管哪一种形式,传递的都不是数组本身,而是
传递第一个数组元素所在内存单元的地址,即数组的起始地址。通过传递数组的起始地址, 
被调用函数可得到数组的准确存放位置。因此,当被调用函数在函数体中修改数组元素的
值时,实际上是修改该地址所指的内存单元中原数组元素的值。

【例5-4】一个班级有20 名学生,所有学生的英语考试成绩保存在一个一维数组中。