1
第 7章 数 组
C 语言程序设计
2009-7-31
2第 7章 数组本章重点介绍,
7.1 一维数组
7.2 二维数组
7.3 字符数组与字符串
2009-7-31
3
一个人 N门课的成绩怎样存储和处理?
一个班 N门课的成绩怎样存储和处理?,.....
这些数据的特点,具有相同的数据类型。
为了方便地使用这些数据,C语言提供了一种 构造数据类型,数组。
例如:存储学生成绩用 实型数组 score[5]
其中,score是数组名。 该数组可以存放 5个成绩,
分别用下标变量表示:
score[0],score[1],?score[4] 。
下标变量 也称为 数组元素 。
提出问题:
2009-7-31
47.1 一维数组例如,int a[10];
float score[5];
,数据类型,,是数组元素的数据类型。
“数组名,,遵循 C语言 标识符规则。
,常量表达式,:表示数组中有多少个元素,即数组的长度。它可以是整型常量、整型常量表达式或符号常量。
7.1.1 一维数组的定义数据类型 数组名 [常量表达式 ];
2009-7-31
5
以下数组定义是正确的:
#define N 10
……
float score1[N],score2[N];
int num[10+N];
char c[26];
以下数组定义是不正确的:
int array(10);
int n; float score[n];
double b['a'.,'d'];
char str[ ];
7.1.1 一维数组的定义(续)
2009-7-31
6数组在内存的存放
数组下标从 0开始。
一维数组的数组元素在内存里 按顺序 存放。
数组名代表数组的首地址,即 score的值与 score[0] 的地址值相同。
score[0]
score[1]
score[2]
score[3]
score[4]
91.5
34.5
67.5
72.0
84.0
低地址高地址
score数组
2009-7-31
77.1.2 数组元素的引用格式:
例如:输入学生成绩
for(i=0;i<5;i++)
scanf("%f",&score[i]);
例如,fib[n]=fib[n-1]+fib[n-2];
下标表达式 的值必须是 整型表达式 。
数组名 [下标表达式 ]
2009-7-31
87.1.2 数组元素的引用(续)
说明,
① 下标从 0开始(下界为 0),数组的最大下标
(上界)是数组长度减 1。
例如:
int a[10];
scanf ("%d",&a[10]); /* 下标越界 */
C编译系统不做越界检查,如果引用的数组元素超出数组范围会破坏其他变量的值。
2009-7-31
97.1.2 数组元素的引用(续)
② [ ]是 下标运算符,
引用 数组元素 时,
根据数组的 首地址和 下标 数,计算出该元素的实际地址,
取出该地址的 内容进行操作。
如引用 score[2]:
(1)计算 2000+2*4=2008
(2)取出 2008的内容
2000H
2004H
2008H
200CH
218CH
score[0]
score[1]
score[2]
score[3]
score[4]
91.5
34.5
67.5
72.0
84.0
2009-7-31
107.1.3 一维数组的初始化初始化:在定义数组时给数组元素赋初值。
1.在定义数组时,对全部数组元素赋初值例如,int a[5]={0,1,2,3,4};
此时可以省略数组长度,例如,int a[ ]={0,1,2,3,4};
2.在定义数组时,对部分数组元素赋初值例如,int a[5]={1,2,3};系统为其余元素赋 0 。
3.当初值的个数多于数组元素的个数时,编译出错例如,int a[5]={0,1,2,3,4,5};
2009-7-31
117.1.4 一维数组应用举例
【 例 7.1】 将 10个人的成绩输入计算机后按逆序显示。
#define N 10
#include<stdio.h>
void main( )
{ int i;float score[N];
for (i=0; i<N; i++)
scanf("%f",&score[i]);
for (i=N-1; i>=0; i--)
printf("%6.1f",score[i]);
} 运行情况如下:
67 74 89 92 34 67 83 95 73 78?
78.0 73.0 95.0 83.0 67.0 34.0 92.0 89.0 74.0 67.0
2009-7-31
12【 例 7.2】 输入 5个整数,找出最大数和最小数所在位置,并把二者对调,然后输出。
思路:
求最大 /小值采用打擂台的方法。
定义一维数组 a存放被比较的数。
定义变量 max:最大值,min:最小值,
k:最大值下标,j:最小值下标 。
各数依次与擂主进行比较,
若 a[i]>max 则,max=a[i]; k=i;
否则判断,若 a[i]<min 则,min=a[i]; j=i;
当所有的数都比较完之后,将 a[j]=max; [k]=min;
输出 a数组。
2009-7-31
13#include<stdio.h>
void main( )
{ int a[5],max,min,i,j,k;
for(i=0; i<5; i++)
scanf("%d",&a[i]);
min=a[0]; max=a[0];
j=k=0;
for (i=1; i<5; i++)
if (a[i]<min) { min=a[i]; j=i; }
else if (a[i]>max) { max=a[i]; k=i ; }
a[j]=max; a[k]=min;
for (i=0; i<5; i++)
printf("%5d",a[i]);
printf("\n");
}
程序运行情况如下:
5 7 2 3 1?
5 1 2 3 7
2009-7-31
14
3
7
5
6
8
0
5
76
7
0
8
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
j=2
3
5
6
7
0
8
0
7
j=3
3
5
6
0
7
8
0
6
j=4j=1
3
5
0
6
7
8
0
5
j=5
3
0
5
6
7
8
0
3
【 例 7.3】 冒泡法排序(从小到大)。
如果 a[ i ] > a[ i+1 ]
a[ i ] 与 a[ i+1 ]交换
(单击继续 … )
以 6个数,3,7,5,6,8,0为例。
2009-7-31
15冒泡法排序 (续)
3
5
6
7
0
8
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
j=2
3
5
6
0
7
8
j=3
3
5
0
6
7
8
j=4j=1
3
0
5
6
7
8
j=5
0
3
5
6
7
8
j 控制 比较的趟数 (外层循环 ):
for(j=1;j< ;j++)
i 控制 两两比较的次数 (内层循环 ):
for (i=0; i< ; i++)
N
N-j
2009-7-31
16冒泡法排序 (续)
从上述过程可以看到,n个数要比较 n-1趟,而在第 j趟比较中,要进行 n-j次两两比较。
冒泡法排序
for (i=0; i<N; i++)
输入 a[i]
for (j=1;j<N; j++)
for (i=0; i<N-j; i++)
a[i]>a[i+1]
T F
a[i]与 a[i+1]交换输出 a[0]~a[N-1]
2009-7-31
17
#define N 6
#include<stdio.h>
void main( )
{ int a[N];
int i,j,t;
for (i=0; i<N; i++)
scanf("%d",&a[i]);
for (j=1; j<=N-1; j++) /*控制比较的趟数 */
for (i=0; i<N-j; i++) /*两两比较的次数 */
if (a[i]>a[i+1])
{ t=a[i];a[i]=a[i+1];a[i+1]=t; }
printf("The sorted numbers,\n");
。。。
}
程序运行情况如下:
3 7 5 6 8 0?
0 3 5 6 7 8
2009-7-31
18
以 6个数,3,7,5,6,8,0为例。
思路:
第一趟:将 第一个数 依次和后面的数比较,如果后面的某数小于 第一个数,则两个数交换,比较结束后,第一个数 则是 最小 的数。
第二趟,将 第二个数 依次和后面的数比较,如果后面的某数小于 第二个数,则两个数交换,比较结束后,第二个数 则是 次小 的数; …… 。
【 例 7.4】 定位比较交换法排序(从小到大)。
2009-7-31
19
3 7 5 6 8 0
3 7 5 6 8 0
3 7 5 6 8 0
3 7 5 6 8 0
3 7 5 6 8 00 3
不交换不交换不交换不交换
a[1] a[2] a[3] a[4] a[5]a[0]
第一趟
j=0
交换
【 例 7.4】 定位比较交换法 排序(续)。
2009-7-31
20
0 7 5 6 8 3
0 3 7 6 8 5j=1
0 3 5 7 8 6j=2
0 3 5 6 8 7j=3
0 3 5 6 7 8j=4
j=0
a[1] a[2] a[3] a[4] a[5]a[0]
【 例 7.4】 定位比较交换法排序(续)。
2009-7-31
21#define N 5
#include<stdio.h>
void main( )
{ int a[N];
int i,j,t;
for (i=0; i<N; i++)
scanf("%d",&a[i]);
printf("\n");
for (j=0; j<N-1; j++) /*确定基准位置 */
for(i=j+1; i<N; i++)
if (a[j]>a[i])
{ t=a[j];a[j]=a[i];a[i]=t; }
printf("The sorted numbers,\n");

}
程序运行情况如下:
96 78 65 86 40?
The sorted numbers,
40 65 78 86 96
2009-7-31
22【 例 7.5】 选择法排序
对定位比较交换法排序的改进以 6个数,3,7,5,6,8,0为例。
思路:
第一趟:将 第一个数 依次和后面的数比较,如果后面的某数小于 第一个数,则将较小的数的下标记录下来。
比较结束后,将记录的下标中的元素与第一个数交换,
第一个数 则是 最小 的数。
第二趟,将 第二个数 依次和后面的数比较,如果后面的某数小于 第二个数,则将较小的数的下标记录下来。
比较结束后,将记录的下标中的元素与 第二个数 交换,
第二个数 则是 第二小 的数。
2009-7-31
23
#include "stdio.h"
void main()
{
int a[5];
int i,j,k,t;
for(i=0;i<5;i++)
scanf("%d",&a[i]);
for(i=0;i<4;i++)
{
k=i;
for(j=i+1;j<5;j++)
if(a[k]>a[j]) k=j;
if(k!=i)
{t=a[i];a[i]=a[k];a[k]=t;}
}
for(i=0;i<5;i++)
printf("%4d",a[i]);
}
2009-7-31
24排序算法比较
冒泡排序:
– 原理容易理解,但效率非常低。
– 循环比较次数和交换次数都较高。
选择排序:
– 循环比较次数和冒泡一致,但交换次数明显降低,效率比冒泡要高。
2009-7-31
257.2 二维数组数据类型 数组名[常量表达式 1][常量表达式 2];
例如,float x[2][3];
7.2.1 二维数组 的定义

X[0][0] X[0][1] X[0][2]
X[1][0] X[1][1] X[1][2]
int a[3,4],b(3,4),c[ ][ ],d(3)(4);
2009-7-31
26
x[0][0]
x[0][1]
x[0][2]
x[1][0]
x[1][1]
x[1][2]
2000H
2004H
2008H
200cH
2010H
2014H
地址 值 数组元素二维数组 元素 在内存中 的 排列顺序,按行存放
2009-7-31
27
x[0]是数组名,是元素 x[0][0]的地址
x[1]是数组名,是元素 x[1][0]的地址二维数组可看作是一种特殊的一维数组
x[0]---- x[0][0],x[0][1],x[0][2]
x[1]---- x[1][0],x[1][1],x[1][2]
例如,可以把 x数组看作是包含二个元素的一维数组,
每个元素又是一个含有三个元素一维数组。
2009-7-31
28
a[3][4]=3; /* 下标越界 */
a[1,2]=1; /* 应写成 a[1][2]=1; */
7.2.2 二维数组元素的引用例,int a[3][4];
a[0][0]=3;
a[0][1]=a[0][0]+10;
数组名 [行下标表达式][列下标表达式]
数组元素的表示形式,
2009-7-31
297.2.3 二维数组的初始化例,int a[2][3]={1,2,3,4,5,6};
1.按行赋初值例,int a[2][3]={{1,2,3},{4,5,6}};
初始化后结果,1 2 3
4 5 6
2.按数组元素在内存中排列的顺序对各元素赋初值
3.给部分元素赋初值例,int a[2][3]={{1},{4}};
初始化后结果,1 0 0
4 0 0
2009-7-31
307.2.3 二维数组的初始化(续)
4.数组初始化时,行长度可省,列长度不能省例如,int a[][3]={1,2,3,4,5,6,7};
int b[][4]={{1},{4,5}};
初始化结果:
a 结果,
a[0],1 2 3
a[1],4 5 6
a[2],7 0 0
b 结果:
b[0],1 0 0 0
b[1],4 5 0 0
2009-7-31
31
下面对二维数组的定义都是错误的:
7.2.3 二维数组的初始化(续)
float x[3][ ]={1.0,2.0,3.0,4.0,5.0,6.0};
int a[ ][ ],b[ ][2],c[3][ ];
int m[2][4]={1,2,3,4,5,6,7,8,9};
/* 编译出错,初值个数多于数组元素的个数 */
2009-7-31
327.2.4 二维数组应用举例
【 例 7.5】 给一个 4行 3列的二维数组输入 /出数据。
#include<stdio.h>
void main( )
{ int a[4][3],i,j,k;
for (i=0; i<4; i++)
for (j=0; j<3; j++)
scanf("%d",&a[i][j]);
for (i=0; i<4; i++)
{ printf("\n");
for (j=0; j<3; j++)
printf("%d\t ",a[i][j]);
}
printf("\n");
}
程序运行情况如下:
1 2 3?
4 5 6?
7 8 9?
10 11 12?
1 2 3
4 5 6
7 8 9
10 11 12
2009-7-31
337.2.4 二维数组应用举例(续)
【 例 7.6】 有一个 N× M矩阵,编程序求出其中绝对值最大的那个元素的值及其所在的行、列位置。
查找最大元素
max=|a[0][0]|,row=0,colum=0
for (i=0; i<N; i++)
for (j=0; j<M; j++)
|a[i][j]|>max
T F
max=|a[i][j]|
row=i
colum=j
输出绝对值 最大的元素及行列下标
2009-7-31
34#include "math.h"
#define N 4
#define M 5
#include<stdio.h>
void main( )
{ int i,j,row,colum,max,a[N][M];
… … /* 输入数据 */
max=a[0][0]; row=colum=0;
for (i=0; i<N; i++)
for (j=0; j<M; j++)
if (abs(a[i][j])>max)
{ max=abs(a[i][j]);
row=i;
colum=j;
}
… … /* 输出数据 */
}
程序运行情况如下:
34 56 12 67 23?
12 67 43 98 54?
65 45 66 16 24?
37 83 25 64 19?
max=98,row=1,colum=3
2009-7-31
357.3 字符数组与字符串字符数组,
可以存放若干个 字符,也可以存放 字符串 。
7.3.1 基本概念
C h i n a \0
字符串:
字符串的末尾必须有 ’\0’字符,它的 ASCII码值为 0。
C h i n a
不是字符串是字符串
2009-7-31
36
再例如:
char a[3][5];
a数组是一个二维的字符数组,可以存放 15个字符或 3个长度不大于 4的字符串。
7.3.2 字符数组的定义例如:
char s[10];
s数组是一维字符数组,它可以存放 10个字符或一个长度不大于 9的字符串。
注意:字符串只能存放在字符数组中。
2009-7-31
377.3.3 字符数组的初始化
C h i n a
1.用字符常量赋初值例如,char c[5]={'C','h','i','n','a' };
再例如:
char c[6]={'C','h','i','n','a','\0'};
C h i n a \0
是字符串不是字符串
2009-7-31
387.3.3 字符数组的初始化(续)
再例如:
char a[3][10]={"basic","pascal","c"};
a s t r i n g \0 \0
2.用字符串常量赋初值例如:
char str[10]= {"a string"}; 或 char str[10]= "a string";
b a s i c \0 \0 \0 \0 \0
p a s c a l \0 \0 \0 \0
c \0 \0 \0 \0 \0 \0 \0 \0 \0
是字符串吗?
2009-7-31
397.3.3 字符数组的初始化(续)
例如,char s3[7]={ 's','t','r','i','n','g'};
G o o d m o r n i n g ! \0
3.初始化时长度的省略例如,char s1[ ]= "Good morning!";
b[0] b[13]
例如,char s2[ ]={ 's','t','r','i','n','g'};
s t r i n g
s t r i n g \0
思考:哪个数组存放的是字符串?
2009-7-31
407.3.4 字符数组的引用
【 例 7.7】 对字符数组 c1赋 '0'~ '9',对字符数组 c2赋 'A'~ 'Z',然后输出 c1和 c2数组中的数据。
1.对字符数组元素的引用可以为 数组元素 赋值,也可以输入 /输出 元素的值。
2009-7-31
41程序如下:
#include<stdio.h>
void main( )
{ char c1[10],c2[26]; int i;
for (i=0; i<10; i++)
c1[i]=i+48;
for (i=0; i<26; i++)
c2[i]=i+'A';
for (i=0; i<10; i++)
printf("%c ",c1[i]);
printf("\n");
for (i=0; i<26; i++)
printf("%c ",c2[i]);
printf("\n");
}
2009-7-31
422.对字符数组的整体引用
⑴ 输出字符串例如:
char c[ ]= "China";
printf("%s",c);
输出结果为:
China C是数组首地址输出时遇 '\0' 为止再例如:
char c[ ]="pascal\0basic";
printf("%s",c);
输出结果为:
pascal
2009-7-31
432.对字符数组的整体引用(续)
⑵ 输入字符串例如:
char c[10];
scanf("%s",c);
输入:
beijing?
b e i j i n g \0
三个字符串用空格隔开,分别赋给 str1,str2,str3三个数组。
再例如:
char str1[10],str2[10],str3[10];
scanf( "%s%s%s",str1,str2,str3);
输入:
pascal basic c?
注意:不可以为数组整体赋值,例如:
char c[10]; c="beijing" ;
因为 c是数组首地址,是常量!?
2009-7-31
447.3.5 字符串处理函数说明:
① 程序中如果调用下面介绍的 8个字符串处理函数,
在程序的开始应该写,
#include "stdio.h" 或 #include "string.h"
预处理命令,但在 Turbo C中可以省略。
② 在字符串处理函数中,凡是用数组名或字符串首地址作参数的地方,都可以用指针变量作参数。
指针变量的概念在第 10章介绍。
2009-7-31
451.字符串输出函数 puts( )
调用格式,puts(str)
功能,输出一个字符串,输出后自动换行 。
说明,str可以是字符数组名或字符串常量。
例如,
char str1[ ]= "China";
char str2[ ]= "Beijing";
puts(str1);
puts(str2);
输出结果:
China
Beijing
2009-7-31
462.字符串输入函数 gets( )
调用格式,gets(str)
功能,从键盘读入一个字符串存入 str数组中,并且得到一个函数值,该函数值是 str数组的首地址。
说明,str是数组名。
程序运行情况如下:
How are you
Fine thank you,?
How are you?
Fine thank you.
例如,
#include<stdio.h>
void main( )
{ char c1[20],c2[20];
gets(c1); gets(c2);
puts(c1); puts(c2);
}
2009-7-31
473.字符串连接函数 strcat( )
调用格式,strcat(str1,str2)
功能,把 str2中的字符串连接到 str1字符串的后面,结果放在 str1数组中,函数值是 str1的值。
b e i j i n g a n d s h a n g h a i \0
必须足够大输出结果:
beijing and shanghai
例如:
char str1[21]="beijing and ";
char str2[ ]="shanghai";
printf("%s",strcat(str1,str2));
2009-7-31
484.字符串复制函数 strcpy( )
调用格式,strcpy(str1,str2)
功能,将 str2中的字符串复制到 str1数组中。
B e i j i n g \0
s1必须足够大思考:这样赋值
s1="Beijing" ;或 s1=s2;可以吗?为什么?
s1的结果例如:
char s1[10],s2[ ]= "Beijing";
strcpy(s1,s2);
或,strcpy(s1,"Beijing");
2009-7-31
495.字符串比较函数 strcmp( )
调用格式,strcmp(str1,str2)
a b c d e \0str1
a b c d e \0str2
a b c \0
a b c d e \0
a b c d \0
A b c d e \0
str1
str2
str1
str2
strcmp(str1,str2)==0
strcmp(str1,str2)>0
strcmp(str1,str2)<0
2009-7-31
50例如:比较两个字符串的大小。
void main( )
{ char s1[ ]= "aBC",s2[ ]= "abc";
if (strcmp(s1,s2)==0) printf("s1=s2");
else if (strcmp(s1,s2)>0) printf("s1>s2");
else printf("s1<s2");
} 程序输出结果:
s1<s2
思考:若有语句
if (s1= =s2) printf("s1=s2");比较的是什么?
2009-7-31
516.求字符串长度函数 strlen( )
调用格式,strlen(str)
功能,测试字符串长度。函数值就是 str中字符的个数。
思考:
字符串 "China"和 str数组在内存中各占几个字节?
输出结果:
5
例如:
char str[10]= "China";
printf("%d",strlen(str));

printf("%d",strlen("China"));
2009-7-31
527.大写字母转换成小写字母函数 strlwr( )
调用格式,strlwr(str)
功能,将 str字符串中的大写字母转换成小写字母。
输出结果:
micro soft word
输出结果:
abcd
例如:
char str[ ]="MICRO SOFT WORD" ;
strlwr(str);
puts(str);
例如:
printf("%s",strlwr("AbCd"));
2009-7-31
538.小写字母转换成大写字母函数 strupr( )
调用格式,strupr(str)
功能,将 str字符串中的小写字母转换成大写字母。
输出结果:
PASCAL
例如:
char ch[10]="pascal";
printf("%s",strupr(ch));
2009-7-31
547.3.6 字符数组应用举例
【 例 7.8】 从标准输入设备上输入一个字符串,分别统计其中 每个数字,空格,字母 及 其他字符 出现的次数。
思路,用 gets( )函数读字符串,然后判断每一个字符是否是 数字,空格,大小写字母 或 其他字符,用循环实现。
注意,此题要求 分别 统计 每个数字 出现的次数,而不是统计数字出现的总次数。
用一个一维整型数组存放每个数字出现的次数。
2009-7-31
55……
{ char s[80]; int i,sp=0,oth=0,lett=0; int dig[10]={0};
gets(s);
for (i=0; s[i]!='\0'; i++)
if (s[i]>='0'&&s[i]<='9') dig[s[i]- '0' ]++;
else if (s[i]==' ') sp++;
else if
(s[i]>='A'&&s[i]<='Z'||s[i]>='a'&&s[i]<='z' )
lett++;
else oth++;
for (i=0; i<10; i++)
printf("%d:%d g ",i,dig[i]);
printf("\nspace:%d letter:%d
other:%d\n",sp,lett,oth);
}
程序运行情况如下,
China 1949.10.1~2004.10.1?
0:4g 1:5g 2:2g 3:0g 4:1g 5:0g 6:0g 7:0g 8:0g 9:2g
space:1 letter:5 other:5
2009-7-31
567.3.6 字符数组应用举例 (续)
【 例 7.9】 输入某月份的整数值 1~ 12,输出该月份的英文名称。
I l l e g a l m o n t h,\0
J a n u a r y \0

D e c e n m b e r \0
思路,将 12个英文月份以字符串的形式存放到
month[13][15]中,一行存放一个字符串。
2009-7-31
57#include<stdio.h>
void main( )
{char month[ ][15]={"Illegal month.",
"January","February","March","April",
"May","June","July","August",
"September","October","Novenber","Decenmber"};
int m;
printf("\nInput month:");
scanf("%d",&m);
printf("%d:%s\n",m,(m<1||m>12)?month[0]:month[m]);
} 程序运行情况如下:
Input month:10?
10,October
2009-7-31
587.3.6 字符数组应用举例 (续)
【 例 7.10】 将 N个国家名按字母顺序排序后输出。
思路,从键盘输入 N个国家名称存放到一个二维字符数组中,然后用 选择法 对这 N个字符串 排序 。
程序如下,
#define N 5
#define M 10
#include "stdio.h"
void main( )
{char s[N][M],str[M];
int i,j;
2009-7-31
597.3.6 字符数组应用举例 (续)
for(i=0;i<N;i++)
gets(s[i]);
for(i=0;i<N-1;i++)
for(j=i+1;j<N;j++)
if(strcmp(s[i],s[j])>0)
{ strcpy(str,s[i]);
strcpy(s[i],s[j]);
strcpy(s[j],str);
}
for(i=0;i<N;i++)
puts(s[i]);
}
选择法排序
2009-7-31
60
第七章结束