第五章:数组
在此之前,所介绍的数据都是属于基本类型(整型、字符
型、实型),C语言还提供了构造类型的数据,它们有:数组
类型、结构体类型、共用体类型。构造类型是由基本类型数
据按一定规则组成的,因此有的书称它们为“导出类型”。
本讲介绍的数组,数组是有序数据的集合。数组中的每
一个元素都属于同一个数据类型。用一个统一的数据名和下
标来唯一地确定数组中的元素。 数组可以是一维的,也可以
是多维的,许多重要的应用都是基于数组的。学习本讲后,
要求理解数组下标,掌握初始化数组的方法,学会把数组用
作函数参数,学会二维数组的使用,并学习数组应用的技术。
一维数组的定义和引用
? 一维数组的定义
? 一维数组元素的引用
? 一维数组的初始化
? 一维数组程序举例
一维数组的定义
数组是一个由若干个同类型变量组成的集合。一维数组的说明
方法为数据类型加数组名,再加方括号,里面含有元素个数。
即,
类型说明符 数组名 [常量表达式 ]
例如:下面的代码说明一个整数数组
int a[10];
它表示数组名为 a,此数组有 10个元素。
说明,
1。数组名命名规则和变量名相同,遵循标识符命名规则。
2。数组名后是用方括号括起来的常量表达式,不能用圆括号,
下面方法不对,
int a(10);
3。常量表达式表示元素的个数,即数组长度。例如,a[10]
中 10表示 a数组有 10个元素,下标从 0开始,这 10个元素是:
a[0],a[1]……a[9] 。注意不能使用数组元素 a[10]。
4。常量表达式中可以包括常量和符号常量,不能包含变量。
也就是说,C不允许对数组的大小作动态定义,即数组的大
小不依赖于程序运行过程中变量的值。例如,下面这样的定
义数组是不行的,
int n;
scanf(“%d”,&n);
int a[n];
……
一维数组元素的引用
数组必须先定义,然后使用。 C语言规定只能逐个引用数组元
素而不能一次引用整个数组。
数组元素的引用形式为,
数组名 [下标 ]
下标可以是整型常量或整型表达式。例如,
a[0]=a[5]+a[7]-a[2*3]
数组元素的使用一般与循环结构结合在一起。请看下例,
例题分析
例 L5-0-1:把 0—9这十个数字赋给一个一维数组,然后按逆序输
出。
main()
{ int i,a[10];
for(i=0;i<=9;i++)
a[i]=i;
for(i=9;i>=0;i--)
printf(“%d,”,a[i]);
}
思考题
把 26个大写字母从‘ A’——‘Z’赋给一维字符数组,然后按逆
序输出。 例 L5-0-2
main()
{ char i,a[26];
for(i=?A? ; i<=?Z? ;i++)
a[i-65]=i;
for(i=?Z?;i>=?A?;i--)
printf(“%c,”,a[i-65]);
}
一维数组的初始化
可以用赋值语句或输入语句使数组中的元素得到值,但占用运行时
间。可以使数组在程序运行之前初始化,即在编译之前得到初值。
对数组元素的初始化可以用以下方法实现,
1、在定义数组时对数组元素赋以初值。例如,
static int a[10]={0,1,2,3,4,5,6,7,8,9};
将数组元素的初值依次放在一对花括号内,请注意:在 int的前面有
一个关键字 static,表明它是“静态存储”的数组。
静态和外部存储( extern)数组默认的初值为 0或空字符。
2、可以只给一部分元素赋值,例如,
static int a[10]={0,1,2,3,4};
定义 a数组有 10个元素,但花括号内只提供 5个初值,这表示只给前
面 5个元素赋初值,后面 5个元素值为 0。
3、如果想使一个数组中全部元素值为 0,即可以写成
int a[10]={0,0,0,0,0,0,0,0,0,0}; 也可以写成
int a[10]={0}; 即第一个元素为 0,其余没有指定默认为 0。
不能写成,int a[10]={0*10};
4、在对全部数组元素赋初值时,可以不指定数组长度。例
如,static int a[5]={1,2,3,4,5};
可以写成 static int a[]={1,2,3,4,5};
5、但若被定义的数组长度与提供的初值的个数不相同,则
数组长度不能省略。
6、静态数组不赋初值时,各值为 0或“空”;动态数组则为
随机值。
数组作为函数的参数
1、数组元素作为参数:与一般变量相同,
属于“值传递”。 例 L5-0-3
2、数组名作为参数:属于地址传递方式,
即直接对地址操作,返回变化的结果。
形参中的一维数组,可以不指定元素的
个数,因为它只是告诉编译程序数组的
地址(起始地址)。 例 L5-0-4
一维数组程序举例
例 L5-0-5:用数组来处理求 Fibonacci数列,
程序如下;
main()
{ int i;
int f[20]={1,1};
for(i=2;i<20;i++)
f[i]=f[i-2]+f[i-1];
for(i=0;i<20;i++)
{ if(i%5==0)printf(“\n”);
printf(“%12d”,f[i]);}
}
一维数组程序举例
例 L5-1,输入 10名学生的成绩,求平均分,并将低于平均分的成绩
打印出来。
例 L5-2,用比较法对 10个数排序(由小到大) —全在主函数中完成。
例 L5-2-0,用比较法对 10个数排序(由小到大) —用分函数中完成。
例 L5-2-1,用起泡法对 10个数排序(由大到小) —用分函数中完成。
例 L5-2-2,用选择法对 10个数排序(由大到小) —用分函数中完成。
排序演示
对半法查找 (例 L5-3)
8 13 21 28 35 41 52 63 71 76 81 95 101 150 164
Top Bot Mid
Bot Top Mid
Bot Top Mid
Bot Top Mid
二维数组的定义和引用
? 二维数组的定义
? 二维数组的引用
? 二维数组的初始化
? 二维数组的程序举例
二维数组的定义
二维数组的定义方式如下,
类型说明符 数组名 [常表达式 ][常量表达式 ];
例如,int X[3][2];
表示数组 X是一个 3*2二维数组,共有 3行 2列,共有 6个元素,每个
元素都是 int型。
二维数组的应用与矩阵有关,其中,从左起第一个下标表示行数,
第二个下标表示列数。与一维数组相似,二维数组的每个下标也是
从 0开始的。
数组中的每个元素都具有相同的数据类型,且占有连续的存储空间,
一维数组的元素是按照下标递增的顺序连续存放的,
二维数组元素的排列是按行进行的,即在内存中,先按顺序排列
第一行的元素,然后,再按顺序排列第二行的元素,以此类推。
如:上面定义的 X数组的元素在内存中排列顺序为,
X[0][0],X[0][1],X[1][0],X[1][1],X[2][0],X[2][1];
m× n 的二维数组 a的元素 a[i][j]在内存中的顺序号为 i× m+j。
二维数组元素的引用
二维数组元素的表示形式如下,
数组名 [下标表达式 ][下标表达式 ]
其中,下标表达式可以是整型常量、整型变量及其表达式。
如,int X[3][2];
它共有 6个元素,分别用 X[0][0],X[0][1],X[1][0],X[1][1],
X[2][0],X[2][1]来表示。
可用下面的语句把 10赋给 X数组中第 0行、第 1列的元素。
X[0][1]=10;
对基本数据类型的变量所能进行的各种运算,也都适合于同
类型的二维数组元素。如,
X[1][1]=X[0][0]*2;
X[2][1]=X[0][0]/2+X[1][1];
二维数组元素的地址也是通过,&”运算得到的。如 X[1][1]元素的地
址可表示为 &X[1][1]。
如时从键盘上为二维数组元素输入数据,一般需要使用双重循环,
同时可采用两种方式:一种是按行输入方式,既先输入第 1行,然
后再输入第 2行,以此类推;另一种方式是按列输入方式,既先输
入第 1列,然后输入第 2列。采用哪一种方式,完全取决于程序的需
要。
下面的语句是按行的方式从键盘上为 X数组的每个元素输入数组,
for(i=0;i<3;i++)
for(j=0;j<2;j++)
scanf(“%d”,&x[i][j]);
二维数组的初始化
可以利用下面方法对二维数组初始化,
?分行给二维数组赋初值。如,
static int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
?可以将所有数据写在一个花括弧内,按数组排列的顺序 对
各元素赋初值。如,
static int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
?可以对部分元素赋初值。
static int a[3][4]={{1},{5},{9}};
它的作用是只对各行第1列的元素赋初值,其余元素值自动
赋为0。赋初值后数组各元素为,
?
?
?
?
?
?
?
?
?
?
0009
0005
0001
也可以对各行中的某一元素赋初值,
int a[3][4]={{1},{0,6},{0,0,11}};
初始化后的数组元素如下,
?
?
?
?
?
?
?
?
?
?
01100
0060
0001
这种方法对非0元素少时比较方便,不必将所有的0都写
出来,只需输入少量数据。
也可以只对某几行元素赋初值,
static int a[3][4]={{1},{5,6}};
数组元素为,
?
?
?
?
?
?
?
?
?
?
0000
0065
0001
?如果对全部元素都赋初值(即提供全部初始数据),则
定义数组时对第一维的长度可以不指定,但第二维的长度
不能省略。如,
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
与下面的定义等价,
int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12};
系统会根据数据的总个数分配存储空间,一共12个数据,
每行4列。当然可确定为3行。
在定义时也可以只对部分元素赋初值而省略第一维的长度。
但应分行赋初值。如,
static int a[ ][4]={{0,0,3},{},{0,10}};
举例,
例 L5-4 对三维数组赋值。
例 L5-4-2:从键盘上为一个 5*5整型数组赋值,找出其中的最小
值并显示出来。
思考题
将一个二维数组行和列元素互换,存到另一个二维数组中例如,
?
?
?
?
?
??
654
321
a
?
?
?
?
?
?
?
?
?
?
?
63
52
41
b
关于学习 C的再建议
?一定要主动学习。
?熟读课本,并找出课本中的错误。
?大量查阅课外资料(参考书、学习软件、网上专题
等)。(花课内 2倍以上的时间)
?大量练习(课内上机 2倍以上的时间)
?纸上谈兵
?上机实践
o 要带着思想来上机
o 要带着程序来上机
o 要带着问题来上机
二维数组复习
? 要以二维方式访问数组元素,则在声明函数时,
应指明形参数组的行与列。
– 例 L5-6-0
? 要以一维方式访问数组元素,则在声明函数时,
可以只指明应指明形参数组的首地址。
– 例 L5-6-1
? 不能直接以一维方式访问二维数组元素。
– 例 L5-6-2
字符数组 1
?字符数组:存放字符数据的数组,一个元素存放一个字符。
?字符数组的定义
类型说明符 数组名 [常量表达式 ]
例,char a[10] 或 int a[10] (为什么? )
表示定义了一个名为 a的一维字符数组,共有 10个元素。
?字符数组的初始化 1
? char a[10]={'I',' ','a','m',' ','h','a','p','p','y'};
? 如果 {}内的数据多于定义的长度,则出错;
? 若少于定义的长度,则其余元素自动赋为 ‘ \0’。 (P130.c)
例,char a[8]={'h','a','p','p','y'}; 则存储状态为,
h a p p y \0 \0 \0
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7]
字符数组 2
?字符数组的初始化 2
? 直接用字符常量初始化字符数组,
char a[10]={"I am happy"};
或 char a[10]="I am happy";
? 不定义长度的初始化
char a[]={"I am happy"};
或 char a[]="I am happy";
与前面定义的并不等价,因为前面的没有结束标志 (见图一 ),而不定
义长度时,自动加上 ‘ \0’(见图二)。
I a m h a p p y \0
I a m h a p p y 图一
图二
字符数组 3
?字符串和字符串结束标志
? C语言中,将字符串作为数组来处理。
? 为了测定字符串的实际长度,C语言中规定了一个字符串结
束标志,'\0'。
? 字符串结束标志,'\0'可以由系统自动加上(上一个例子),
也可人为加上。
字符数组输入、输出 1
例 7.6 (L7-6.c) 逐个输入一个字符串,并逐个输出。
main( )
{
char c[12];
int i;
clrscr( );
printf("Input a string:");
for(i=0;i<10;i++)
scanf("%c",&c[i]);
for(i=0;i<10;i++)
printf("%c",c[i]);
getch( );
}
?字符数组的输入、输出
?逐个输入、输出。
字符数组输入、输出 2
例 7.6-2 (L7-6-2.c) 整个字符串一次输出
main( )
{
char c[80];
int i;
clrscr( );
printf("Input a string:");
scanf("%s",c);
printf("%s",c);
getch( );
}
?字符数组的输入、输出
?整个字符一次输入、输出。
字符数组输入、输出 3
?字符数组一次输入、输出注意事项
? 输出字符不包括结束符 ‘ \0’。
(参见 p133.c)
? 输出时遇到 ‘ \0’便结束,不管后面是否有字符。
( 参见 p134.c )
? 用 %s格式输出时,输出项是数组名,而不是数组元素名。
printf("%s",c[0]); 是错的。
? 在 scanf( )函数中,输入项为数组名时,不要再加地址符 &,而数组
名就代表其起始地址。
? 输出字符数组时,
先按数组名,找到数组的起始地址,
然后逐个输出其中的字符,直到遇到
‘ \0’为止。 (参见 P131.c)
C
h
i
n
a
\0
2000
2001
2002
2003
2004
2005
字符串处理函数 1
例,main() (P135.c)
{ char str[]="China \nBeijing";
puts(str); /*输出 */
printf("输入一个字符串,");
gets(str); /*输入 */
printf("输出该字符串,");
puts(str); /*输出 */
printf("该字符数组的起始地址为,%u",str); getch();
}
?puts(字符数组 ):将一个以 ‘ \0’结束的字符串输出到终端,
字符串中可以包含 转义符 。
?gets(字符数组 ):从终端输入一个字符串到字符数组,并得
到一个函数值(字符数组的起始地址)
字符串处理函数 2
?strcat(字符数组 1,字符数组 2) string catenate(字符串连接 )
char s1[]="People's Republic of "; P136.c
char s2[]="China";
printf("%s",strcat(s1,s2));
运行结果,People's Republic of China
?Strcpy(字符数组,字符串数组 ) string copy(字符串复制)
char s1[10]; p137.c
char s2[]="China";
strcpy(s1,s2);
printf("%s",s1);
运行结果,China
注意,字符串的复制不能写成 s1=s2。
字符串处理函数 3
main()
{char str1[80],str2[80];
printf("Input str1[]=");
gets(str1);
printf("Input str2[]=");
gets(str2);
if(strcmp(str1,str2)= =0) printf("两个字符串相等。 ");
else if(strcmp(str1,str2)>0) printf("str1大于 str2。 ");
else printf(“str1小于 str2。, );
}
例,p137-2.c
输入两个字符串
比较其大小。
?strcmp(字符串 1,字符串 2) string compare(字符串比较 )
?字符串 1=字符串 2,结果为 0
?字符串 1>字符串 2,结果为正整数
?字符串 1<字符串 2,结果为负整数
字符串处理函数 4
例 p138.c
main()
{
char s1[]="I must study hard.";
char s2[]="I HAVE A computer.";
printf("\The length of s1 is:%d",strlen(s1)); /*长度 */
printf("\nuppercase(s1)=%s",strupr(s1));/*转换为大写 */
printf("\nlowercase(s2)=%s",strlwr(s2));/*转换为小写 */
}
?strlen( 字符数组 ),string length:测试字符数组的长度
?Strlwr(字符串 ),string lowercase:字符串转换成小写
?Strupr(字符串 ),string uppercase:字符串转换成大写