1
第七章 数组
引言
7.1 一维数组的定义和引用
7.2 二维数组的定义和引用
7.3 字符数组
2
引言一、数组的引入为了便于处理一批类型相同的数据,引入了数组类型这种方法只能求所有学生的总成绩,
而不能保留住每个学生的成绩。
假设现在 要求保存每个学生的成绩,
那就不能只使用一个变量 s了,
而需要 40个变量,但这样一来输入、
输出、计算都会变得繁琐,在这种情况下,我们可以使用数组类型,
说明一个含有 40个元素的数组,每个数组元素存放一个成绩,成绩的输入、
输出、计算都可通过循环来实现例,某班有 40名学生,求该班成绩的平均分
#include <stdio.h>
void main( )
{ int j,sum,s ;
float ave ;
sum=0;
for(j=1; j<=40 ; j++)
{ scanf(“%d”,&s);
sum=sum+s;
}
ave=sum/40 ;
printf(“ave=%f”,ave);
}
3
二、数组的概念
1.数组,由具有相同类型的固定数量的元素组成的结构
2.数组元素,每一个数组元素都是一个变量,为了与一般的变量相区别,我们称数组元素为 下标变量
3.下标变量在数组中的位置序号称 下标下标变量的数据类型称为下标类型 (或元素类型 )
#include <stdio.h>
void main( )
{ int j,sum,s[40] ;
float ave ;
sum=0;
for(j=0; j<=39 ; j++)
{ scanf(“%d”,&s[j]);
sum=sum+s[j];
}
ave=sum/40;
printf(“ave=%f”,ave);
}
4
7.1 一维数组的定义和引用一,一维数组的定义
1,格式,类型标识符 数组名 [ 常量表达式 ] ;
例,int a[10] ;
2,说明
(1) 数组名 是用户定义的标识符,
数组名表示了一个存储区的首地址
(即第一个数组元素的地址 )
(2) 数组长度,指数组中元素的个数
(3) 数组元素的下标 由零开始数组 a 有 10个元素,a[0],a[1] … a[9]
(4) 常量表达式 中不能包含变量,
常量表达式的值 不能是实数
84
:
66
80
951010
1012
1014
:
1028
a[0]
a[1]
a[2]
:
a[9]
5
二,数组元素的引用
1,引用形式,数组名 [ 下标 ]
注意,如果出现 a[5] = 72 ; 编译时不会指出错误,系统会将 a[4]后下一个存储单元 赋值为 72,但这样可能会破坏数组以外其他变量的值
84
75
66
80
951010
1012
1014
1016
1018
a[0]
a[1]
a[2]
a[3]
a[4]
72 a[5]1020
假设这个存储空间是变量 x的,实际上 a[5]是不存在的,如果执行了
a[5]=72,会将 x原有的正确数据覆盖掉
2,说明
(1) 下标可以是整型常量或整型表达式如,a[1],a[2*3]
(2) 数组定义为 int a[5],数组长度为 5
而下标在 0 ---- 4之内,即 a[0] ---- a[4]
6
三,一维数组的初始化
1,概念,在定义一维数组时对各元素指定初始值称为数组的初始化 如,int a[5] = { 1,3,5,7,9 } ;
2,说明
(1) 对数组的全体元素指定初值,初值用 { } 括起来,数据之间用逗号分开,在这种情况下,可以不指明数组的长度,系统会根据 { }内数据的个数确定数组的长度如,int a[ ] = { 1,3,5,7,9 } ;
(2) 对数组中部分元素指定初值 ( 这时不能省略数组长度 )
如,int a[5] = { 1,3,5 };
(3) 使数组中的全部元素初始值都为 0
如,int a[5] = { 0,0,0,0,0 } ;
更简单的写法,int a[5]={ 0 } ;
7
例 1,用数组求 fibonacci数列的前 20个数
#include <stdio.h>
void main( )
{ int i,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%4==0 )
printf(“\n”);
printf(“%6d”,f[i] );
}
}
1
1
0
0
0
0
:
0
f[0]
f[1]
f[2]
f[3]
f[4]
f[5]
:
f[19]
2
3
5
8
6765
i=2
f[2]=f[0]+f[1]
i=3
f[3]=f[1]+f[2]
i=4
f[4]=f[2]+f[3]
8
例 2,输入一个数据,在已知数组中查找是否有该数据
5
8
0
1
9
2
6
3
7
4
x 9 a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
a[6]
a[7]
a[8]
a[9]
#include <stdio.h>
void main()
{ int i,x ;
int a[10]={ 5,8,0,1,9,2,6,3,7,4 };
inputf (“\n input a number:”) ;
scanf(“%d”,&x);
for ( i=0 ; i<10 ; i++)
if ( x==a[i] )
{ printf(“find!\n”);
break;
}
if ( i==10 )
printf(“no find!\n”);
}
9
例 3,用冒泡排序法对 6个数进行排序 (从小到大 )
9
7
2
5
4
1
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
7
2
5
4
1
9
2
7
7
5
4
71
2
5
4
1
7
9
4
51
5
2
4
1
5
7
9
2
1
4
5
7
9
1
4
1
2
冒泡排序方法,依次比较相邻的两个数,将小数放前面,
大数放后面,n个数排序需要进行 n-1轮比较,从第 1轮到第 n-1轮,各轮的比较次数依次为,n-1次,n-2次 … 1次
9
7
2
5
4
19
9
9
9
9
7
2
5
4
1
初始状态 第 1轮 第 2轮 第 3轮 第 4轮 第 5轮
7
10
#include <stdio.h>
void main( )
{ int a[6],i,j,t;
for ( i=0 ; i<6 ; i++)
scanf(“%d”,&a[i] );
for ( i=0 ; i<5 ; i++)
for ( j=0 ; j<5-i ; j++)
if ( a[j]>a[j+1] )
{ t=a[j] ;
a[j]=a[j+1] ;
a[j+1]=t ;
}
for ( i=0 ; i<6 ; i++)
printf(,%3d”,a[i] );
}
输入 6个数据用嵌套的 for循环实现排序外层循环控制进行几轮比较内层循环控制每一轮的比较次数如果前面的数大于后面的数,则进行交换输出排序后的 6个数据
11
9
7
1
2
4
5
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
7
1
2
4
5
9
1
2
4
5
7
9
1
2
4
5
7
9
1
2
4
5
7
9
第 1轮 第 2轮 第 3轮 第 4轮 第 5轮
1
2
4
5
7
9
从这道例题中我们发现,在进行完第二轮比较后,实际上排序已经完成了,从第三轮开始,后面的比较都是多余的,
在这种情况下我们希望可以终止比较,
初始状态冒泡排序的改进:
12
为了解决问题,我们在程序中设置一个变量 flag,用它记录在一轮比较中是否进行了交换,
在每轮比较开始前 flag=0,如果在此轮比较中进行了交换,
则 flag=1,在一轮比较结束后,
判断 flag的值是否为 1,如果值为 0,说明在此轮比较中没有进行交换 (即已经完成排序了 ),
此时可以终止循环 (即结束排序 )如果 flag的值为 1,则要继续进行排序
#include <stdio.h>
void main( )
{ int a[6],i,j,t,flag;
for ( i=0; i<6; i++)
scanf(“%d”,&a[i] );
i=0 ;
do
{ flag=0;
for ( j=0 ; j<5-i ; j++)
if ( a[j]>a[j+1] )
{ t=a[j] ; a[j]=a[j+1] ;
a[j+1]=t ; flag=1;
}
i++ ;
}
while ( flag ) ;
for ( i=0 ; i<6 ; i++)
printf(,%3d”,a[i] );
}
13
例 4,用选择排序法对 6个数进行排序 (从小到大 )
9
7
2
5
4
1
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
选择排序方法,第 1轮比较时,用 a[0]依次与 a[1]到 a[5]
进行比较,如果 a[0]较大则进行交换,第 1轮结束后,a[0]
中为最小数,以后各轮比较过程与第 1论类似,
1
9
7
5
4
2
1
2
9
7
5
4
7
9
5
7
4
5
2
4
1
2
4
9
7
5
1
2
4
5
7
9
7
9
5
7
4
5
9
7
2
5
4
1
72
9
7
1
2
初始状态 第 1轮 第 2轮 第 3轮 第 4轮 第 5轮
7
9
5
7
14
#include <stdio.h>
void main( )
{ int a[6],i,j,t;
for ( i=0 ; i<6 ; i++)
scanf(“%d”,&a[i] );
for ( i=0 ; i<5 ; i++)
for ( j=i+1 ; j<6 ; j++)
if ( a[i]>a[j] )
{ t=a[i] ;
a[i]=a[j] ;
a[j]=t ;
}
for ( i=0 ; i<6 ; i++)
printf(,%3d”,a[i] );
}
i=0 时,要进行 5次比较,a[0]与 a[1]比,
a[0]与 a[2]比 … a[0] 与 a[5]比,最后 a[0]
中为最小数
i=1 时,要进行 4次比较,a[1]与 a[2]比,
a[1]与 a[3]比 … a[1] 与 a[5]比,最后 a[1]
中为第 2小的数
i=2 时,要进行 3次比较,a[2]与 a[3]比,
a[2]与 a[4]比,a[2]与 a[5]比,最后 a[2]
中为第 3小的数
15
分析排序过程我们发现,在每一轮的比较中交换次数太多,
我们可以尽量减少交换次数,实际上每轮比较只要一次交换就能完成排序,
对选择排序进行改进,其方法如下,
先从要排序的 n个数中 找出最小的数,把它放在第一个位置,
再从剩下的 n-1个数中找出最小的数,把它放在第二个位置,
这样重复做下去改进后的选择排序方法数据进行比较的次数并没有减少,
但每一轮只进行一次交换,加快了程序运行速度
16
9
7
2
5
4
1
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
0k 12
1
9
1
7
2
5
4
9
5!=0
a[0]和 a[5]换
5 k 12
2
7
2!=1
a[1]和 a[2]换
1
2
7
5
4
9
4!=2
a[2]和 a[4]换
k 234
4
7
设置变量 k用以存储当前最小数的下标 #include <stdio.h>void main( )
{ int a[6],i,j,k,t;
for ( i=0 ; i<6 ; i++)
scanf(“%d”,&a[i] );
for ( i=0 ; i<5 ; i++)
{ k=i ;
for ( j=i+1 ; j<6 ; 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<6 ; i++)
printf(,%3d”,a[i] );
}
17
7.2 二维数组的定义和使用一,二维数组的定义
1,概念,一个一维数组,它的 每一个元素都是类型相同的一维数组,就形成一个二维数组
2,定义形式,
类型标识符 数组名 [ 常量表达式 1 ] [ 常量表达式 2 ]
如,int a[3][4] ;
a[2][0] a[2][1] a[2][2] a[2][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[0][0] a[0][1] a[0][2] a[0][3]
18
3,存储形式,数组的元素在内存中是连续存放的
int a[3][3] ; 的存放形式如下,
a[1][0]?a[1][1]?a[1][2]
a[2][0]?a[2][1]?a[2][2]
a[0][0]?a[0][1]?a[0][2] a[0][0]
a[0][1]
a[0][2]
a[1][0]
a[1][1]
a[1][2]
a[2][0]
a[2][1]
a[2][2]
1010
1012
1014
1016
1018
1020
1022
1024
1026
二,二维数组的引用数组元素的表示形式,
数组名 [下标 ] [下标 ]
注意,(1) 每个下标都要用 [ ] 括起来如 a [2] [1] 不能写成 a [2,1]
(2) 下标不要超过定义的范围
19
三,二维数组的初始化
1,分行初始化
int a[3][4]={ { 1,2,3,4 },{ 5,6,7,8 },{ 9,10,11,12 } };
此方法较直观,第一对 { }内的数据赋给第一行数组元素,以此类推
2,按数据的排列顺序对数组元素赋初值
int a[3][4]={ 1,2,3,4,5,6,7,8,9,10,11,12}
将数据依次赋给元素 a[0][0],a[0][1] ……a[2][3]
1 2 3 4
5 6 7 8
9 10 11 12
注意,此方法数据没有明显的界限,当数据较多时容易出错
20
3,对数组的部分元素赋初值
int a[3][4]={{ 1,2 },{ 3 },{ 0,4 }}; int a[3][4]={ 1,2,3,4,5,6 };
1 2 0 0
3 0 0 0
0 4 0 0
1 2 3 4
5 6 0 0
0 0 0 0
4,对数组的全部元素赋初值时 可以省略第一维的长度系统会根据数据的个数和第二维的长度自动求出第一维的长度
int a[ ][4]={ {1,2},{ 0,3,4 },{ 5 } } ;
int b[ ][2]={ 1,2,3,4,5,6,7,8 } ;
数组 a 第一维长度为 3
数组 b 第一维长度为 4
21
例 5,找出矩阵中最大的数,并输出其行号和列号
5 2 0 9
3 7 12 6
10 4 1 8
max
0row
0col
59
3
12
1
2
#include <stdio.h>
void main( )
{ int i,j,row=0,col=0,max ;
int a[3][4]={{5,2,0,9},{3,7,12,6},{10,4,1,8}};
max=a[0][0];
for ( i=0 ; i<3 ; i++ )
for ( j=0 ; j<4 ; j++ )
if ( a[i][j]>max )
{ max=a[i][j] ;
row=i ; /* row中放行数 */
col=j ; /* col 中放列数 */
}
printf(“max=%d\n”,max);
printf(“max=a[%d][%d]\n”,row,col);
}
输出,
max=12
max=a[1][2]
22
3
7
12
6
10
4
1
8
5
2
0
9
例 6,将一个矩阵进行转置 (即原来的行变为列 )
5 2 0 9
3 7 12 6
10 4 1 8
#include<stdio.h>
void main( )
{ int a[3][4],b[4][3],i,j ;
for ( i=0 ; i<3 ; i++ )
for ( j=0 ; j<4 ; j++ )
scanf(“%d”,&a[i][j] ) ;
for ( i=0 ; i<3 ; i++ )
for (j=0 ; j<4 ; j++)
b[j][i]=a[i][j];
for ( i=0 ; i<4 ; i++ )
{ for ( j=0 ; j<3 ; j++ )
printf(“%5d”,b[i][j] ) ;
printf(“\n”);
}
}
输入数组 a
进行矩阵转置输出数组 b
a[0][
2]
b[2][
0]
a[2][
1]
b[1][
2]
23
7.3 字符数组一,字符数组和字符串
1,字符数组定义,char c[10];
2,字符串,由若干个有效字符组成的序列有效字符包括 字母,数字,专用字符,转义字符如,,bfer”,a45-7”,m\tk\n”
3,字符串的存储
C语言中没有专门的字符串变量,因此 字符串存放在字符数组中,字符串 以,\0”作为结束标志例,char c[5] ;
① c[0]=?O? ; c[1]=?K? ; c[2]=?!? ; O K !
O K ! \0② c[0]=?O?; c[1]=?K?; c[2]=?!?; c[3]=?\0? ;
注意,字符数组与字符串并不相同
24
二,字符数组的初始化
1,为数组中的 元素指定初值
char c[8] = {?H?,?e?,?l?,?l?,?o? } ;
如果对数组全部元素指定初值,则可以省略数组的长度
char c[ ] = {?H?,?e?,?l?,?l?,?o? } ;
H e l l o \0 \0 \0
H e l l o
2,对字符数组指定 字符串初值
char c[8] = {,Hello” } ;
char c[8] =,Hello” ;
char c[8] = {?H?,?e?,?l?,?l?,?o?,?\0? } ;
三种形式等价
char c[ ] =,Hello”; char c[6]=“Hello”;
char c[5] =,Hello” ;
H e l l o \0
H e l l o \0 错误的初始化注意,初始化时数组的长度应足够大,
确保可以容纳所有字符和结束标志‘ \0?
25
三,字符串的输入
1,输入单个字符
char c[8] ;
int i ;
scanf(“%c%c%c”,&c[0],&c[1],&c[2] ) ;
for ( i=0 ; i<8 ; i++ )
scanf(“%c”,&c[i] ) ;
2,输入一个字符串
scanf (,%s”,c ) ;
说明,用格式字符 %s输入字符串,字符数组变量 c不需要加地址运算符 &,因数组名本身代表数组的首地址注意,(1) 从键盘输入字符串时不加,”
(2) 用 scanf 输入字符串时,空格和回车符都会作为字符串的分隔符,即 scanf不能用来输入包含有空格的字符串
26
3,字符串输入函数 gets ( 字符数组 )
如,gets(c) ;
说明,输入有空格的字符串时应使用函数 gets,
它会读入全部字符直到遇到回车符为止例,int i ;
char c[8];
① for ( i=0 ; i<8 ; i++ )
scanf(“%c”,&c[i] ) ;
② scanf(“%s”,c ) ;
③ gets ( c ) ;
假设输入为,abcd efgh↙
a b c d e f g
a b c d \0
a b c d e f g h \0
注意,用 gets输入字符串时,若输入字符数目大于字符数组的长度,多出的字符则会存放在数组的合法存储空间之外
27
四,字符串的输出
1,输出单个字符
char c[8] = {?H?,?e?,?l?,?l?,?o? };
int i ;
printf(,%c%c”,c[0],c]1] ) ;
for ( i=0 ; i<8 ; i++ )
printf(,%c”,c[i] ) ;
2,输出字符串 printf(,%s”,c ) ;
注意,输出时不包括字符‘ \0?,如果一个字符串中有多个‘ \0?
则输出时遇到第一个‘ \0?即认为字符串结束3,字符串输出函数 puts ( 字符数组 )
一次输出一个字符串,输出时将‘ \0?自动转换成换行符
28
例,char s1[5]=“abc”,s2[10]=“defg” ;
printf(,%s%s\n”,s1,s2 ) ;
puts( s1 ) ;
puts( s2 ) ;
输出结果,
abcdefg
abc
defg
例,int i ;
char c[8];
gets ( c ) ;
for ( i=0 ; i<8 ; i++ )
printf(“%c”,c[i] );
printf(“\n”)
puts ( c );
printf(“%s”,c );
假设输入为,abcd efgh↙
a b c d e f g h \0
输出结果,
abcd efg
abcd efgh
abcd efgh
29
五、字符串处理函数 (使用字符串函数时要写 #include <string.h>)
1,字符串拷贝函数注意,C语言不允许用赋值表达式对字符数组赋值
char s1[5]=“abc”,s2[3],s3[8] ;
s2 =,abc” ;
s3 = s1 ;
/* 赋值与初始化不同 */
/* 对 s2,s3 的赋值都是非法的 */
希望字符数组 s2或 s3中也存放字符串,abc”不能用赋值而要用 字符串拷贝函数
(1) 格式,strcpy( 字符数组变量 1,字符串 2 )
(2) 作用,将字符串 2中的字符复制到字符数组 1中
(3) 说明,
① 字符数组 1 必须足够大
②字符串可以是字符串常量,也可以是字符数组变量
③拷贝时‘ \0?也一起拷贝
30
例,char s1[5]=“abc”,s2[3],s3[8] ;
strcpy ( s3,s1 ) ;
strcpy ( s2,s1 ) ;
a b c \0
a b c \0s1
s3
a b c \0s2
函数 strncpy( 字符数组 1,字符串 2,n )
作用,将字符串 2的前 n个字符复制到字符数组 1 中例,char c1[10],c2[ ]=“abcdef” ;
strncpy( c1,c2,3 ) ;
c1
a b c d e f \0c2
a b c
31
2,字符串连接函数
(1) 格式,strcat ( 字符数组变量 1,字符串 2 )
(2) 作用,将字符串 2中的字符连接到字符串 1 的后面,产生的新字符串仍存放在字符数组 1 中
(3) 说明,连接时将字符串 1 末尾的‘ \0?将去掉,而在连接后的新字符串末尾添加‘ \0?
注意,字符数组 1要足够大例,char s1[10]=“abc”,s2[ ]=“def” ;
strcat ( s1,s2 ) ;
strcat ( s1,“gh” ) ;
a b c \0
d e f \0
s1
s2
d e f \0g h \0
32
3,字符串比较函数
(1) 格式,strcmp ( 字符串 1,字符串 2 )
(2) 作用,比较两个字符串的大小
(3) 说明,
① 两个字符串可能是字符串常量或字符数组变量
② 两个字符串比较时,从字符串中的第一个字符开始逐个比较其 ASCII码值,直到出现不同字符或出现‘ \0?为止
③ 比较的结果由函数值带回
str1 = = str2 函数值为 0
str1 > str2 函数值为正数
str1 < str2 函数值为负数
33
例,int n1,n2,n3 ;
char s1[5],s2[5] ;
n1 = strcmp (,abc”,“def” ) ;
strcpy( s1,“dfg” ) ;
strcpy( s2,“you” ) ;
n2 = strcmp ( s1,“def” ) ;
n3 = strcmp ( s1,s2 ) ;
字符‘ a?与‘ d?比较
n1== -3 ( 97-100 )
先‘ d?与‘ d?比较,相同,
然后‘ f?与‘ e?比较
n2==1 ( 102-101)
字符‘ d?与‘ y?比较
n3== -21 (100-121)d f g \0
y o u \0
s1
s2
34
4,测字符串长度函数格式,strlen (字符串 )
作用,测出字符串中实际字符的个数 ( 不包括‘ \0? )
例,int len1,len2 ;
char s[10] ;
len1 = strlen(,computer”) ;
gets(s) ;
len2 = strlen(s) ;
5,字符串中大、小字母转换
strlwr ( 字符串 ) 将字符串中大写字母换成小写字母
strupr ( 字符串 ) 将字符串中小写字母换成大写字母
35
课后作业,P153
7.5,7.12,7.15