第5 章数 组
5.1 基本知识提要
5.1.1 知识结构图

第5 章 数组
5.1.2 重点知识整理
1.数组的概念 
数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据
在数组中的序号。数组中的每一个元素都属于同一种数据类型。
2.一维数组
(1)一维数组的定义。在C语言中使用数组必须先进行定义。一维数组的定义方
式为: 
类型说明符数组名[常量表达式]; 
其中: 
① 类型说明符可以是任意一种基本数据类型或构造数据类型。
② 数组名是用户定义的数组标识符,命名规则遵循标识符命名规则。
③ 方括号中的常量表达式表示数组元素的个数,也称为数组的长度。
例如: 
float b[10], c[20]; //定义浮点型数组b,有10 个元素,浮点型数组c,有20 个元素
char ch[20]; //定义字符数组ch,有20 个元素。
(2)一维数组的引用。一维数组元素的引用格式: 
数组名[下标] 
数组的引用下标取值范围为0到数组长度值-1,不能越限。如用inta[15]定义的
数组,引用时的下标不能超过或等于15,语句a[15]=10是错误的。
定义数组时使用的“数组名[常量表达式]”和引用数组元素时使用的“数组名[下标]” 
形式相同,但含义不同。数组定义的方括号中给出的是数组的长度;而数组元素中的下标
是该元素在数组中的位置标识。前者只能是常量,后者可以是常量、变量或表达式。
(3)一维数组的初始化。数组的初始化就是在定义数组的同时,给其数组元素赋初
值。数组初始化是在编译阶段进行的。这样将减少运行时间,提高效率。
一维数组初始化赋值的一般形式为: 
类型说明符数组名[常量表达式]={数值1,数值2,…,数值n}; 
C语言对数组的初始化有以下几点规定: 
① 可以只给部分数组元素赋初值。当大括号中值的个数少于数组元素个数时,只给
前面部分数组元素赋值。例如: 
int a[10]={0,1,2,3,4}; 
127

C 语言程序设计习题解答与实验指导
相当于只给a[0]、a[1]、a[2]、a[3]、a[4]赋初值,而后5个元素自动赋为0值。
② 只能给数组元素逐个赋值,不能给数组整体赋值。例如,给10个元素全部赋值为
1,只能写为: 
int a[10]={1,1,1,1,1,1,1,1,1,1}; 
而不能写为: 
int a[10]=1; 
③ 如给全部元素赋值,则在数组声明中,可以不给出数组元素的个数。例如: 
int a[5]={1,2,3,4,5}; 
可写为: 
int a[]={1,2,3,4,5}; 
④ 大括号中数值的个数多于数组元素的个数是语法错误。
(4)一维数组排序方法:冒泡排序。冒泡排序是交换排序中一种简单的排序方法。
它的基本思想是对所有相邻数组元素进行大小比较,如果是逆顺(a[j]>a[j+1]),则将其
交换,最终达到有序化。其处理过程为: 
① 将整个待排序的数组元素划分成有序区和无序区,初始状态有序区为空,无序区
包括所有待排序的记录。
② 对无序区从前向后依次将相邻数组元素进行大小比较,若逆序将其交换,从而使
得值小的数组元素向上“飘浮”(或左移),值大的数组元素好像石块,向下“堕落”(或右
移)。每经过一趟冒泡排序,都使无序区中值最大的数组元素进入有序区,对于由n个元
素组成的数据序列,最多经过n-1趟冒泡排序,就可以将这n个元素重新按值从小到大
的顺序排列。
有序序列,第一趟定位第n个记录,此时有序区只有一个记录;第二趟定位第n-1个
记录,此时有序区有两个记录;以此类推,算法框架为: 
for (i=n;i>1;i-) { 定位第i 个记录; } 
对数组元素进行排序的方法有很多种,本章上机实验部分再介绍一种比较简单的选
择排序。更多排序方法将在后续的数据结构课程中学习,目前只需掌握简单的冒泡排序
和选择排序。
(5)一维数组查找方法。
. 顺序查找:就是从第一个元素开始,按索引顺序遍历待查找序列,直到找出给定
目标或者查找失败。
. 折半查找:也称二分查找,它是一种效率较高的查找方法。但是,折半查找要求
数组中的数组元素已有序排列。关于折半查找的详细内容参见本章上机实验
部分。
3.二维数组
(1)二维数组的定义。二维数组定义的一般形式是: 
128

第5 章 数组 
类型说明二维数组名[常量表达式1][常量表达式2]; 
其中常量表达式1表示第一维的长度,常量表达式2表示第二维的长度。例如: 
int x[2][3]; 
x是二维数组名,这个二维数组共有6个元素(2×3=6),它们是x[0][0]、x[0][1]、
x[0][2]、x[1][0]、x[1][1]、x[1][2]。且其全部元素数值均为整型。
(2)二维数组的引用。二维数组元素的引用格式为: 
数组名[下标1][下标2] 
同样要注意引用数组元素时下标不能越限。
(3)二维数组的初始化。二维数组的初始化有两种方法: 
① 把初始化值括在一对大括号内,例如,对于二维数组 
int x[2][3]={1,2,3,4,5,6}; 
初始化结果是:x[0][0]=1,x[0][1]=2,x[0][2]=3,x[1][0]=4,x[1][1]=5, 
x[1][2]=6。
② 把二维数组看作一种特殊的一维数组,该数组的每一个元素又是一个一维数组。
例如: 
int x[2][3]; 
可把数组x看成是具有两个元素的一维数组,其元素是x[0]和x[1]。而每个元素
x[0]、x[1]又都是具有三个元素的一维数组,其元素是x[0][0]、x[0][1]、x[0][2]、
x[1][0]、x[1][1]、x[1][2]。
x:x[0]:x[0][0],x[0][1],x[0][2] 
x[1]:x[1][0],x[1][1],x[1][{ 2] 
因此,上例二维数组的初始化可分解成两个一维数组的初始化: 
int x[2][3]={{1,2,3},{4,5,6}}; 
对于二维数组初始化赋值还有以下几点说明: 
① 可以只对部分元素赋初值,未赋初值的元素自动取0值。例如: 
int x[2][2]={{1},{2}}; 
是对每一行的第一列元素赋值,未赋值的元素取0 值。赋值后各元素的值为: 
x[0][0]=1,x[0][1]=0,x[1][0]=2,x[1][1]=0。
② 如对全部元素赋初值,则第一维的长度可以不给出。例如,二维数组x的初始化
过程: 
int x[2][3]={1,2,3,4,5,6}; 
129

C 语言程序设计习题解答与实验指导
也可写成: 
int x[ ][3]={1,2,3,4,5,6}; 
即第一维的长度省略,但第二维的长度不能省略。
4.字符数组和字符串
(1)字符数组。字符型数组的定义格式: 
char 数组名[字符个数]; 
例如: 
char c[5]; 
字符数组也可以是二维或多维数组。例如: 
char c[3][4]; 
即为二维字符数组。
同样,字符数组也允许在定义时进行初始化赋值。例如: 
char c[4]={'G','o','o','d'}; 
赋值后各元素的值为c[0]= 'G',c[1]='o',c[2]='o',c[3]='d'。如果提供赋值的字
符个数多于数组元素的个数,则为语法错误。
字符型数组与数值型数组在初始化中的区别:初始化时,提供的数据个数如果少于
数组元素个数,则多余的数组元素初始化为空字符\' 0',而数值型数组初始化为0。
(2)字符串。在C 语言中没有专门的字符串类型,C 语言使用字符数组来存放字
符串。存
放字符串的字符数组的初始化有两种方法: 
① 用字符常量初始化数组,用字符常量给字符数组赋初值要用大括号将赋值的字符
常量括起来。例如: 
char str[6]={ 'C', 'h', 'i', 'n', 'a', '\0' }; 
数组str[6]被初始化为"China"。其中最后一个元素的赋值\' 0'可以省略。
② 用字符串常量初始化数组。例如: 
char str[6]="China"; 
或 
char str[6]={ "China"}; 
不管用字符常量初始化字符数组,还是用字符串常量初始化数组,若字符个数少于数
组长度,程序都自动在末尾字符后加\' 0'。
注意: 
① 用字符串常量初始化时,字符数组的长度可以省略,其数组存放字符的个数由赋
130

第5 章 数组
值的字符串的长度决定。
② 初始化时,若字符个数与数组长度相同,则字符末尾不加'\0',此时字符数组不能
作为字符串处理,只能作为字符逐个处理。初始化时是否加'\0',要看是否作为字符串
处理。
(3)字符串处理函数。C 语言标准库函数中,提供了一些专门用于处理字符串的函
数,常用的有scanf()/printf()函数(%s格式)、gets()/puts()函数、strlen()函数、strcmp() 
函数、strlwr()/strupr()函数、strcat()函数、strcpy()/strncpy()函数。
5.2 主教材习题解答
一、选择题
1.D 2. A 3.C 4.D 5.D 6. A 7. A 8.B 9.D 10.C 
11.B 12.D 13.B 14.C 15.B 
二、填空题
1.0、6 
2.2、0、0 
3.windows2000 
4.a[i]、2、i+1 
5.t=i、i、\' 0' 
三、编程题
1. 解题思路:以数组中间的元素为中心,将其两侧对称的元素的值互换即可。
参考代码如下: 
#include <stdio.h> 
#define N 5 
int main() 
{ 
int a[N]; 
int i,j,temp; 
printf("Please enter array a:\n"); 
for(i=0;i<N;i++) 
scanf("%d",&a[i]); //从键盘输入数组元素的值 
printf("array a:\n"); 
for(i=0;i<N;i++) //输出数组 
printf("%4d",a[i]); 
printf("\n"); 
for(i=0;i<N/2;i++) //将数组前后对称位置的元素值进行交换
131

C 语言程序设计习题解答与实验指导 
{ 
j=N-i-1; 
temp=a[i];a[i]=a[j];a[j]=temp; 
} 
printf("reverse array a:\n"); //输出逆序后的数组 
for(i=0;i<N;i++) 
printf("%4d",a[i]); 
printf("\n"); 
return 0; 
} 
2. 解题思路: 
(1)将一年12个月每月的天数存放到一个整型数组days中,2月份天数的初始值
为28。
(2)判断所输入的年份是否是闰年? 若是闰年,修改2月份天数为29。因为平年2 
月是28天,闰年2月是29天。
(3)累加该年该月之前的各月份天数和,存入变量sum,sum 的初始值为0。
(4)sum+输入的天数,即为题目所求。
参考代码如下: 
#include <stdio.h> 
int main() 
{ 
//存放每个月的天数的数组,2 月份的天数初始化为28 天 
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31}; 
int year,month,day; 
int i,sum=0; 
printf("Please enter year,month,day:\n"); 
scanf("%d%d%d",&year,&month,&day); 
if(year%400==0 || (year%4==0 && year%100!=0)) //闰年 
days[1]=29; / /修 改 2 月 份 的 天数为29 天 
for(i=1;i<month;i++) 
sum+=days[i-1]; 
sum+=day; 
printf("%d 年%d 月%d 日是这一年的第%d 天\n",year,month,day,sum); 
return 0; 
} 
3. 解题思路:从数组的第一个元素开始顺序查找,将要找的数与数组中的每个元素
逐一比较,直到找到为止(如果数组中无此数,则应找到最后一个数,然后判断“找不到”)。
参考代码如下: 
#include <stdio.h> 
#define N 10 
132

第5 章 数组
int main() 
{ 
int a[N]={7,20,10,3,9,6,12,15,21,32}; 
int i,x; 
printf("Please enter x:"); 
scanf("%d",&x); 
for(i=0;i<N;i++) //顺序查找,从数组的第一个元素开始比较 
if(a[i]==x) //找到 
{ 
printf("Find,the order of x is: %d",i+1); 
break; 
} 
if(i>=N) //找不到 
printf("Not find! \n"); 
return 0; 
} 
4. 解题思路
(1)使用表达式“rand()%100+1”产生一个大小为1~100的随机数。
(2)产生10个随机数并存入长度为10的整型数组a。
(3)利用改进的冒泡排序对数组a中的元素进行升序排序。
冒泡排序(Bubblesort)是基于交换排序的一种算法。它是依次两两比较待排序元
素,若为逆序(递增或递减)则进行交换。将待排序元素从左至右比较一遍称为一趟“冒
泡”。每趟冒泡都将待排序列中的最大关键字交换到最后(或最前)位置,直到全部元素有
序为止。若本次冒泡处理过程中,没有进行任何交换,说明序列已有序,则停止交换。这
就是改进的冒泡算法的处理思想。可以通过设置标志变量来判断是否提前完成排序。
参考代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#define N 10 
int main() 
{ 
int a[N]; //用于保存10 个随机数 
int i,j,temp,flag; //flag 为标志变量 
srand((unsigned int)time(NULL)); //设置当前时间为种子 
for(i=0; i<10;i++) 
{ 
a[i]=rand() %100 +1; //产生1~100 的随机数 
printf("%d ",a[i]); / /打印生成的随机数 
} 
printf("\n"); 
133

C 语言程序设计习题解答与实验指导 
for(i=N-1;i>0;i--) / /改进的冒泡排序 
{ 
flag=0; //每一趟排序,首先置标志变量flag 的值为0 
for(j=0;j<i;j++) 
if(a[j]>a[j+1]) 
{ 
temp=a[j]; 
a[j]=a[j+1]; 
a[j+1]=temp; 
flag=1; //如果发生数据的交换,置标志变量flag 的值为0 
} 
//如果一趟排序过程中,未发生数据交换,说明数据已有序,则退出循环,提前结束排序 
if(flag==0) break; 
} 
//输出排序后的数组a 
for (i =0; i<10; i++) 
{ 
printf("%d ",a[i]); 
} 
printf("\n"); 
return 0; 
} 
5. 解题思路:假设要插入的数为x,从数组的最后一个元素开始搜索x的插入位置, 
如果数组中的元素比x大,则将此数组元素后移一个位置,并继续往前搜索,直到找到一
个小于或等于x的元素为止,x插入此元素的后面这个位置,该位置已腾空,直接插入x 
即可。如果数组中的所有元素都比x大,则x插入到数组的最前面(下标为0的位置)。
参考代码如下: 
#include <stdio.h> 
#include <time.h> 
#define MAXSIZE 10 
int main() 
{ 
int a[MAXSIZE]={10,20,30,45,45,50}; //非递减有序的数组a 
int size=6; //数组a 的长度为6 
int i,x; 
printf("Please enter x:"); 
scanf("%d",&x); 
//查找x 的插入位置,从后往前查找,边查找边后移比x 大的元素 
i=size-1; 
while(i>=0 && a[i]>x) 
{ 
a[i+1]=a[i]; 
134

第5 章 数组 
i--; 
} 
a[i+1]=x; //插入x 
size++; //数组长度增加1 
for(i=0;i<size;i++)printf("%d ",a[i]); //输出数组 
printf("\n"); 
return 0; 
} 
6. 解题思路:该题采用逐一判断的方式,周边元素的下标一定有0或4,并且只要下
标有一个0或4,则它一定是周边元素。
参考代码如下: 
#include <stdio.h> 
int main() 
{ 
int a[5][5]={0,1,2,7,9,1,11,21,5,5,2,21,6,11,1,9,7,9,10,2,5,4,1,4,1}; 
int i,j; 
int s=0; 
printf("*****The array*****\n"); 
for(i=0;i<5;i++) 
{ 
for(j=0;j<5;j++) 
{ 
printf("%4d",a[i][j]); 
} 
printf("\n"); 
} 
for(i=0;i<5;i++) 
for(j=0;j<5;j++) 
if(i==0||i==4||j==0||j==4) 
s=s+a[i][j]*a[i][j]; 
printf("*****The result*****\n"); 
printf("The sum is:%d\n",s); 
return 0; 
} 
7. 解题思路:以字符串中间的字符为中心,比较其两侧对称的字符是否相等。
参考代码如下: 
#include <stdio.h> 
#include <string.h> 
#define N 10 
int main() 
{ 
135