第5 章数 组
学习了C语言的基本数据类型和程序流程控制结构后,很多问题都可以描述和解决
了。但是对于大规模的数据,尤其是相互间具有一定联系的数据,怎么表示和组织才能达
到高效呢? C语言的数组类型为同类型数据的组织提供了一种有效的形式。
为了更好地理解数组的作用,请考虑这样一个问题:在程序中如何存储和处理具有
n个整数的数列? 如果n很小,比如n等于3时,显然不成问题,简单地声明3个int变量
就可以了。如果n为1000,用int变量来表示这1000个数,就需要声明1000个int变量, 
其烦琐程度可想而知。用什么方法来处理这1000个变量呢? 数组就是针对这样的问题
的,它是用于存储和处理大量同类型数据的一种构造型数据类型。数组是具有一定顺序
关系的同类型数据的集合,这些数据使用相同的名字(即数组名)和不同的下标进行区分, 
我们称之为数组元素。将数组与循环结合起来,可以有效地处理大批量的数据,大大提高
了工作效率,十分方便。
字符串应用广泛,但C语言中没有专门的字符串类型,字符串是使用字符数组来存
放的。同时,C语言标准函数库中提供有专门的字符串处理函数,方便对字符串的处理。
本章介绍在C语言中如何定义和使用数组,包括一维数组,二维数组,以及字符串数
据的存储和处理。
学习目标: 
. 掌握一维数组的定义、引用和初始化。
. 掌握二维数组的定义、引用和初始化。
. 掌握字符数组的定义、引用和初始化。
. 掌握字符串的处理方法,熟悉字符串常用处理函数。
. 熟悉数组基本操作算法,能够正确使用数组解决一般应用问题。
5.1 一维数组
5.1.1 一维数组的定义和引用
1.一维数组的定义 
在C语言中使用数组前必须先进行定义。一维数组的定义方式为:

第5 章 数组 
类型声明符数组名[常量表达式]; 
其中: 
(1)类型声明符是任一种基本数据类型或构造数据类型,即int、float、char等基本数
据类型,以及第9章中将介绍的结构体数据类型。从这里可以看出,数组是建立在其他数
据类型的基础之上的,因此数组是构造类型。
(2)数组名是用户定义的数组标识符,命名规则遵循标识符命名规则。对于数组元
素来说,它们具有一个共同的名字,即数组名。
(3)方括号中的常量表达式表示数组元素的个数,也称为数组的长度。例如: 
float b[10], c[20]; //定义实型数组b,有10 个元素;定义实型数组c,有20 个元素
char ch[20]; //定义字符数组ch,有20 个元素
对于数组定义,应注意以下几点: 
(1)数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元素的
数据类型都是相同的。
(2)数组名不能与其他变量名相同。例如: 
int main() 
{ 
int a; 
float a[10]; //错误,数组名和变量名相同 
… 
return 0; 
}
(3)方括号中常量表达式表示的是数组元素的个数,如a[5]表示数组a有5个元素。
但是其下标从0开始计算,因此这5个元素分别为a[0]、a[1]、a[2]、a[3]、a[4]。
(4)不能在方括号中用变量来表示数组元素的个数,但可以用符号常数或常量表达
式。例如: 
#define D 5 
int main() 
{ 
int a[3+5],b[4+D]; //合法的定义 
… 
return 0; 
}
而下述定义方式是错误的: 
int main() 
{ 
int n=10; 
161

C 语言程序设计 
int a[n]; //不合法的定义,因为n 为变量 
… 
return 0; 
} 
2.一维数组元素的存储
每个数组元素都占用内存中的一个存储单元,每个元素都是一个变量,可以像以前讲
图5.1 一维数组的存储形式
过的普通变量一样使用,只不过数组元素是通过数
组名和方括号中的下标来确定的。系统在内存中
为数组元素分配连续的存储单元。
例如,定义语句inta[15],声明了以下几个
问题:
(1)数组名为a。
(2)数组元素的数据类型为int。
(3)数组元素的下标值从0开始。数组元素的
个数为15,分别是a[0]、a[1]、a[2]、…、a[13]、
a[14]
(4)数组名a是数组存储区的首地址,即存放数
组第一个元素的地址。a等价于&a[0],因此数组名
是一个地址常量。不能对数组名进行赋值或运算。
在这个例子中,数据元素的存储形式如图5.1所示。
3.一维数组元素的引用
对数组元素的引用与对变量的引用类似,但与变量引用不同的是,只能对数组元素进
行引用,而不能一次引用整个数组。一维数组元素的引用格式如下: 
数组名[下标] 
其中: 
(1)下标可以是整型常量或整型常量表达式,如a[3]、a[3+2]。
(2)下标还可以是整型变量或整型变量表达式,如a[i]、a[i+j]、a[i++]。
(3)如果下标是表达式,首先要计算表达式,计算的最终结果为下标值。
(4)下标值从0开始,而不是从1开始。
(5)数组的引用下标不能越限,如用inta[15]定义的数组,引用时的下标不能超过或
等于15,即a[15]=10是错误的。
定义数组时使用的“数组名[常量表达式]”和引用数组元素时使用的“数组名[下标]” 
形式相同,但含义不同。在数组定义的方括号中给出的是数组的长度,而在数组元素中的
下标是该元素在数组中的位置标识,下标取值范围为0到数组长度值减1。前者只能是
162

第5 章 数组
常量,后者可以是常量、变量或表达式。
【例5-1】 从键盘输入10个整数,求其中的最大数并输出。
【问题分析】
(1)定义一个一维数组,数组长度为10,用于存储从键盘输入的10个整数。
(2)求一组数的最大数:首先假定第一个数最大,把该数放到变量max中,然后依次
处理后面9个数,如果当前正在处理的这个数比max还大,则更改max的值为这个数。
将数组与for循环相结合,可以轻松完成此任务。
解决该问题的算法流程图如图5.2所示。
【程序代码】 
#include <stdio.h> 
int main() 
{ 
int a[10]; //定义整型数组a 
int i,max; //定义循环控制变量i 和存放最大数的变量max 
printf("Please enter ten integers:\n"); //输出屏幕提示语 
for(i=0;i<=9;i++) //循环10 次 
scanf("%d",&a[i]); //从键盘接收数据,并存放到数组元素a[i]中 
for(i=0;i<=9;i++) / /循 环 10 次 
printf("%d ",a[i]); //输出数组元素a[i]的值 
max=a[0]; / /给 m ax 变量赋值,假定第一个数最大 
for(i=1;i<=9;i++) / /循 环 9 次 
if(max<a[i]) /*比较max 与数组中当前正在处理的数组元素的大小,将较大者赋给
max*/ 
max=a[i]; 
printf("\nThe max is %d\n",max); //输出求得的最大数 
return 0; 
}
【运行结果】
程序运行结果如图5.3所示。
【代码解析】
(1)main()函数中的inta[10]是数组的定义语句,定义一个长度为10的整型数组, 
用于存储从键盘输入的10个整数。
(2)main()函数中的第一个for循环,实现从键盘接收10个整数,并存放到数组
a中。
(3)main()函数中的第二个for循环,实现把10个整数输出到屏幕。
(4)main()函数中的第三个for循环,实现求10个整数中的最大数。在此段代码中,变
量max用来存放当前已比较过的各数中的最大数。开始时设max的值为a[0],然后将max 
与a[1]比较,如果a[1]大于max,则max重新取值为a[1],下一次以max的新值与a[2]比
较,如果a[2]大于max,则max重新取值为a[2],此时max的值是a[0]、a[1]、a[2]中的最大
数。以此类推,经过9轮循环的比较,max最后的值就是10个数中的最大数。
163

图5.-1的流程图

2 例5

461
C 
语言程序设计


第5 章 数组
图5.3 例5-1程序运行结果 
(5)最后一条输出语句输出求得的最大数。
说明:此示例只是为了演示一维数组的定义与引用。在实际问题中,如果只是要求
找出一组数中的最大或者最小数,那么这组数据可以不保存,采用边读边求最大或者最小
数的方式,程序更简洁、高效,实现代码参见例4-7。
【例5-2】 有等差数列an =5×n+1,要求分别按正序和逆序输出该数列的前10项
到屏幕。n 为0~9的整数。
【问题分析】
(1)计算数列的第n项的值:通过示例中给出的数列通项公式计算即可。
(2)由于示例要求逆序输出数列的前10项,故需要一个长度为10的整型数组来存
储数列的前10项的值。
(3)数组与for循环相结合,完成数列前10项的计算、存储、正序和逆序输出。
【程序代码】 
#include <stdio.h> 
int main() 
{ 
int a[10]; //定义整型数组a 
int n; //定义循环控制变量n 
for(n=0;n<=9;n++) / /循环10 次,计算数列的前10 项,并按正序输出 
{ 
a[n]=5*n+1; / /计 算 数 列的第n 项的值,并赋给第n 个数组元素 
printf("a[%d]=%d ",n,a[n]); //输出数列的第n 项的值 
} 
printf("\n"); / /换 行 
for(n=9;n>=0;n--) / /循环10 次,逆序输出数列的前10 项 
{ 
printf("a[%d]=%d ",n,a[n]); 
} 
printf("\n"); 
return 0; 
}
【运行结果】
程序运行结果如图5.4所示。
165

C 语言程序设计
图5.4 例5-2程序运行结果
【代码解析】
(1)mian函数中的语句inta[10],定义一个长度为10的整型数组a,用于存储数列
的前10项。
(2)main函数中的第一个10次的for循环,循环控制变量从0开始依次递增1,实现
求数列的前10项,数列的第n项存储到数组元素a[n]中,并正序输出。
(3)main函数中的第二个10次的for循环,循环控制变量从9开始依次递减1,实现
逆序输出数列的前10项。
5.1.2 一维数组的初始化
与一般变量的初始化一样,数组的初始化就是在定义数组的同时,给其数组元素赋初
值。数组初始化是在编译阶段进行的,这样将减少运行时间,提高效率。
一维数组初始化赋值的一般形式为: 
类型声明符数组名[常量表达式]={数值1,数值2,…,数值n}; 
其中赋值号右边大括号中的各数据值即为各数组元素的初值,各值之间用逗号间隔。
例如: 
int a[3]={0,1,2}; 
相当于 
a[0]=0;a[1]=1;a[2]=2; 
C语言对数组的初始化有以下几点规定: 
(1)可以只给部分数组元素赋初值。当大括号中值的个数少于数组元素个数时,只
为前面部分数组元素赋值。例如: 
int a[10]={0,1,2,3,4}; 
相当于只为a[0]、a[1]、a[2]、a[3]、a[4]赋初值,而后5个元素自动赋为0值。
(2)只能给数组元素逐个赋值,不能给数组整体赋值。例如,给10个元素全部赋值
为1,只能写为: 
int a[10]={1,1,1,1,1,1,1,1,1,1}; 
166

第5 章 数组
而不能写为: 
int a[10]=1; 
(3)如给全部元素赋值,则在数组声明中,可以不给出数组元素的个数。例如: 
int a[5]={1,2,3,4,5}; 
可写为: 
int a[]={1,2,3,4,5}; 
(4)大括号中数值的个数多于数组元素的个数是语法错误。
5.1.3 一维数组应用举例
【例5-3】 参照例4-16中提出的兔子问题,应用数组计算2年后有多少对兔子? 
【问题分析】
根据题意,以f[n]表示n个月以后兔子的总对数,其规律为f[n]=f[n-2]+f[n-1],如
此构成的数列如下: 
f[1]=1,f[2]=1,f[3]=2,f[4]=3,f[5]=5,…,f[n]=f[n-2]+f[n-1],… 
即斐波那契数列。此问题转化为求斐波那契数列第24项的值,其算法流程图如图5.5 
所示。
【程序代码】 
#include <stdio.h> 
int main() 
{ int n, f[25]; //定义整型变量n,整型数组f 
f[1]=f[2]=1; //为f[1]和f[2]赋初值1 
for(n=3;n<=24;n++) //循环22 次 
f[n]=f[n-1]+f[n-2]; //计算f[n]的值 
for(n=1;n<=24;n++) //输出数列中所有项的值 
{ if((n-1)%4==0) //每输出4 个数后换行 
printf("\n"); 
printf("%10d",f[n]); //输出数列中第n 项的值 
} 
printf("\n"); 
return 0; 
}
【运行结果】
程序运行结果截图如图5.6所示。
说明:很多数列的问题都可以类似于上述的斐波纳契数列的计算方法,用数组来进
行存储和计算。
167

图5.-3的流程图

5 例5


图5.-3程序运行结果

6 例5

861
C 
语言程序设计


第5 章 数组 
【例5-4】 给定n 个任意数,按由小到大对其排序,并输出排序结果。
【问题分析】
这个问题是一组数的排序问题,排序方法有多种,这里采用冒泡排序法。
冒泡排序法的思路是,将相邻两个数比较,将小的数调到前头(或将大的数调到后
面)。比如有5个数,分别是7、6、10、4、2,依次将其放入数组a中。我们看一下冒泡排序
法的处理过程。
(1)第一趟(如图5.7所示),经过4次比较。
第1次:将第1个数a[0]和第2个数a[1]进行比较,将较大的数调到下面。也就是
说,若后面的数小,就将两数交换,否则不交换。这里把7和6对调位置,结果如图5.7(b) 
所示。第
2次:将第2个数a[1]和第3个数a[2]进行比较,将较大的调到下面。这里是7 
和10比较,这次比较不用对调这两个元素的位置,结果如图5.7(c)所示。
第3次:将第3个数a[2]和第4个数a[3]进行比较,将较大的调到下面。这里是10 
和4比较后对调位置,结果如图5.7(d)所示。
第4次:将第4个数a[3]和第5个数a[4]进行比较,将较大的调到下面。这里是10 
和2比较后对调位置,结果如图5.7(e)所示。
图5.7 冒泡排序的第一趟过程
如此进行共4次,结果得到6-7-4-2-10的顺序,最大的数10成为最下面的一个数。
最大的数“沉底”,最小的数2向上“浮起”一个位置(冒第一个泡)。
这4次处理过程都是类似的,都是“相邻两数比较,若后面的数小,则两数交换,否则
不交换”;所不同的是“比较的两个数,它们的位置不同”,先是a[0]和a[1]比较,再是a[1] 
和a[2]比较,然后是a[2]和a[3]比较,最后是a[3]和a[4]比较。我们会发现一个规律, 
每次比较后,往下移了一位,所以可以用一个变量i控制,每次都是a[i]和a[i+1]比较, 
而每次比较完后i+1,总共比较4次,这样就可以用一个循环来实现,即: 
for(i=0;i<4;i++) 
if(a[i]>a[i+1]) 
{ 
temp=a[i]; a[i]=a[i+1]; a[i+1]=temp; 
} 
169