Download presentation
Presentation is loading. Please wait.
1
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
2
问题 请输入300个学生的数学成绩并打印出来,如何完成? 分析:首先定义300个变量准备存储这300个学生的数学成绩
float m1,m2,m3,…,m300; 然后输入300个学生的数学成绩 scanf(“%d,%d,…,%d”,&m1,&m2,…,&m300); 最后打印所有学生的数学成绩 printf(“%d,%d,…,%d”,m1,m2,…,m300);
3
关于数组 数组专用于处理大量同类型数据。数组中的每个元素都属于同一数据类型。
数组是有序数据的集合,用一个统一的数组名和下标来唯一地确定数组中的元素 每一个数组元素都可以当做单个变量来使用
4
数组的定义 int a[10]; 类型说明符 数组名[数组长度]; 定义一个有10个元素的数组,每个元素的类型均为int
使用a[0]、a[1]、a[2]、……、a[9]这样的形式访问每个元素,可以像使用普通变量一样使用他们。 系统会在内存分配连续的10个int空间给此数组 数组的首地址就是数组名a 类型说明符 数组名[数组长度]; 数组名的命名规则同标识符 定义数组时必须指定数组元素的个数,即数组长度 数组长度可以是常量或常量表达式,不能包含变量 int n; scanf(“%d”,&n); int a[n]; a[0] a[1] a[2] a[7] a[8] a[9] …… a
5
数组元素的初始化 同变量一样,数组定义后如果没有初始化,其中的值是不确定的。 (1)在定义时对数组元素进行初始化
int a[10]={ 0,1,2,3,4,5,6,7,8,9 };相当于a[0]=0; a[1]=1; ... a[9]=9; (2)可以只给一部分元素赋值 int a[10]= { 0,1,2,3,4};表示只给前面5个元素赋初值,后面5个元素 初值为0 (3)如果想使一个数组中全部元素值为0,可以写成 int a[10]={0,0, 0,0, 0,0, 0,0, 0,0}或者int a[10]={0}; (4)对数组中全部元素赋初值时,可以不指定数组长度 int a[5]={1,2,3,4,5};可以写成int a[ ]={1,2,3,4,5};
6
数组元素的引用 数组中的每个元素都可以当作变量单独访问 数组元素的表示形式:数组名[下标],下标只能是整型量或者整型表达式
数组元素从0开始标号 下标越界是大忌!
7
一维数组的输入和输出 只能逐个对数组元素进行操作(字符数组例外) 输出方法: 输入方法: 输入数组第i个元素: 输出数组第i个元素:
int a[10],i; 输入方法: 输出方法: 输入数组第i个元素: 输出数组第i个元素: printf("%d",a[i]); scanf("%d",&a[i]); 输入所有数组元素: 输出所有数组元素: for (i=0;i<10;i++) printf("%d",a[i]); for (i=0;i<10;i++) scanf("%d",&a[i]);
8
例6.1 #include <stdio.h> void main() { int i, a[10]; for(i=0;i<=9;i++) a[i]=i; for(i=9;i>=0;i--) printf("%d ",a[i]); }
9
例6.2求Fibonacci数列
10
例6.2 #include <stdio.h> void main( ) { int i; int f[20]={1,2};
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"); /*一行控制为5个数*/ printf("%12d",f[i]); }
11
二维数组的定义 二维数组定义的一般形式: 类型说明符 数组名[常量表达式] [常量表达式]
例如:float a[3][4],b[5][10]; 注意不能写成 float a[3,4],b[5,10]; 定义一个二维数组 float a[3][4]其实就是分配了一个由12个float型元素组成的3行×4列的阵: a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] 也可将二维数组看作是特殊的一维数组:它的每个元素又是一个一维数组 a[0] a[1] a[2]
12
可以看成:float a[0][4],a[1][4],a[2][4]; a[0]---------a00 a01 a02 a03
存放顺序:按行存放,先顺序存放 第0行的元素,再存放第1行的元素 a[0][0] 三个一维数组名 a a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] …… a[1][3] a[2][0] a[2][1] a[2][2] …… a[2][3]
13
二维数组的引用 二维数组的元素的表示形式: 数组名[下标][下标] 下标只能是整型量或者整型表达式
例如: a[2][3], b[2-1][2*2], str[i][j] 二维数组的每个元素同样可当作一个变量进行访问,如: b[1][2]=a[2][3]/2+a[0][0] 常见错误 a[2,3] int a[3][4]; … a[3][4]=3;
14
二维数组的初始化 分行给二维数组初始化 int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
按数组排列的顺序对各元素赋初值 int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 对部分元素赋初值 int a[3][4]={{1},{5},{9}}; 初始化后数组元素取值情况:
15
对各行中的某几个元素赋初值 int a[3][4]={{1},{0,6},{0,0,11}}; 初始化后数组元素取值情况: int a[3][4]={{1},{5,6}};
16
4.如果对全部元素都赋初值,则定义数组时对第一维的长度可以不指定,但第二维的长度不能省
如: 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}; 也可以只对部分元素赋初值 int a[ ][4]={{0,0,3},{ },{0,10}};
17
二维数组的输入和输出 数组的输入和输出只能逐个对数组元素进行操作(字符数组例外) int a[2][3],i,j; 输出方法: 输入方法:
scanf(“%d”,&a[i][j]); 输入整个数组元素: for (i=0;i<2;i++) for(j=0;j<3;j++) 输出方法: 输出第i行第j列元素: printf(“%d”,a[i][j]); 输出整个数组元素: for (i=0;i<2;i++) for(j=0;j<3;j++)
18
例6.3 给定一个二维数组,将其行和列元素互换,存到另一个二维数组中。 3 6
19
#include <stdio.h>
void main( ) { int a[2][3]={{1,2,3},{4,5,6}}; int b[3][2],i,j; printf("array a:\n"); for(i=0;i<=1;i++) for(j=0;j<=2;j++) printf("%5d",a[i][j]); b[j][i]=a[i][j]; } printf("\n"); printf("array b:\n"); for(i=0;i<=2;i++) for(j=0;j<=1;j++) printf("%5d",b[i][j]);
20
例6.4 查找 给定3×4的矩阵,找出所有元素最大的值,以及其所在的行号和列号。 N-S流程图 max=a[0][0]
for i=0 to 2 for j=0 to 3 真 a[i][j]>max 假 max=a[i][j] row=I colum=j 输出:max 和 row,colum
21
#include <stdio.h>
void main( ) { int i,j,row=0,colum=0,max; int a[3][4]={{1,2,3,4},{9,8,7,6},{-10,10,-5,2}}; max=a[0][0]; for(i=0;i<=2;i++) for(j=0;j<=3;j++) if(a[i][j]>max) max=a[i][j]; row=i; colum=j; } printf("max=%d,row=%d,colum=%d\n",max,row,colum);
22
例6.5 冒泡排序 用冒泡法对10个数按由小到大的顺序进行排序 思路:将相邻两个数比较,将小的调到前头 若有6个数: 9 8 5 4 2 0
一共要比较 轮,第i轮需要比较 次 9 8 5 4 2 8 9 5 4 2 8 5 9 4 2 8 5 4 9 2 8 5 4 2 9 8 5 4 2 9 8 5 4 2 5 8 4 2 5 4 8 2 5 4 2 8 5 4 2 8 1 2 3 4 结果 结果 1 2 3 4 5 n-1 n-i
23
第i轮中,已经有i-1个数确定了位置,还剩n-i+1个数,分别是a[0],a[1]…a[n-i]
#include <stdio.h> void main( ) { int a[10]; int i,j,t; for(i=0;i<10;i++) scanf("%d",&a[i]); printf("\n"); for(i=1;i<=9; i++) for(j=0;j<=9-i;j++) if (a[j]>a[j+1]) t=a[j]; a[j]=a[j+1]; a[j+1]=t; } printf("the sorted numbers :\n"); printf("%d ",a[i]); (i从1取值) 第i轮中,已经有i-1个数确定了位置,还剩n-i+1个数,分别是a[0],a[1]…a[n-i] 因此j的范围是从0到n-i-1 (i从0取值) 第i轮中,已经有i个数确定了位置,还剩n-i个数,分别是a[0],a[1]…a[n-i-1] 因此j的范围是从0到n-i-2
24
数组作为函数的参数 数组元素及数组名均可作函数参数。 1. 数组元素作函数实参
数组元素作为实参类似于变量作为实参,采用单向传递,即“值传递”方法。
25
例6.6 数组比较 有两个数组a、b各有10个元素,将它们对应地逐个相比。分别统计两个数组对应元素大于、等于、小于的次数。
a[0] a[1] a[2]…..a[7] a[8] a[9] b[0] b[1] b[2]…..b[7] b[8] b[9]
26
#include <stdio.h>
void main( ) { int large(int x,int y);/*声明*/ int a[10],b[10],i,n=0,m=0,k=0; printf("enter array a:\n"); for(i=0;i<10;i++) scanf("%d",&a[i]); printf("\nenter array b:\n"); scanf("%d",&b[i]); printf("\n"); if(large(a[i],b[i])==1) n=n+1; else if(large(a[i],b[i])==0) m=m+1; else k=k+1; } printf("a[i]>b[i] %d times\na[i]=b[i] %d times \na[i]<b[i] %d times\n",n,m,k);
27
运行时: int large(int x,int y) { int flag; if(x>y)flag=1;
else if(x<y)flag=-1; else flag=0; return(flag); } 运行时:
28
数组名作函数参数,实参与形参都应使用数组名 例6.7 求10个学生的平均成绩
2. 数组名作为函数参数 数组名作函数参数,实参与形参都应使用数组名 例6.7 求10个学生的平均成绩 #include<stdio.h> float average(float a[10]) /*a为数组名,形参*/ { int i; float aver,sum=a[0]; for(i=1;i<10;i++) sum=sum+a[i]; aver=sum/10; return(aver); } void main( ) { float score[10], aver; int i; printf("input 10 score:\n"); for(i=0;i<10;i++) scanf("%f",&score[i]); printf("\n"); aver=average(score);/*score作为实参*/ printf("average score is %5.2f", aver); }
29
说明 数组名作函数参数,主调函数和被调函数应分别定义数组。
用数组名作函数实参时,不是把数组的值传递给形参,而是把实参数组的起始地址传递给形参数组,两个数组共占同一段内存单元,称为“传地址”方式。 实参数组与形参数组类型应一致。 实参数组和形参数组大小可以不一致。C编译对形参数组大小不作检查,只是将实参数组的首地址传给形参数组。形参数组也可以不指定大小,在定义数组时数组名后面跟一个空的方括号。有时为了在被调用函数中处理数组元素的需要,可以另设一个参数,传递需要处理的数组元素的个数。
30
例6.8 求平均成绩 调用方法:average(score_1,5) average(score_2,10)
#include<stdio.h> float average(float array[ ],int n) { int i; float aver, sum=array[0]; for(i=1;i<n;i++) sum=sum+array[i]; aver=sum/n; return(aver); } 调用方法:average(score_1,5) average(score_2,10)
31
运行结果: void main( ) { float score_1[5]={98.5,97,91.5,60,55};
printf("the average of class A is %6.2f\n", average(score_1,5)); printf("the average of class B is %6.2f\n", average(score_2,10)); } 运行结果:
32
例6.9 选择法排序 对数组中10个整数按由小到大排序。 选择法步骤 a[0] a[1] a[2] a[3] a[4]
(未排序) (第一次排序) (第二次排序) (第三次排序) (第四次排序) 选择法排序和起泡法排序的不同: 选择法是:先比较1和2,然后再比较1和3,1和4,1和5, ,1和n。一轮只进行一次交换 起泡法是:先比较1和2,然后再比较2和3,3和4,4和5, ,n-1和n。一轮需要进行多次交换
33
#include<stdio.h>
void sort(int array[ ],int n) { int i,j,k,t; for(i=1;i<=n-1;i++) k=i-1; for(j=i;j<=n-1;j++) if(array[j]<array[k]) k=j; t=array[k]; array[k]=array[i-1]; array[i-1]=t; } void main( ) { int a[10],i; printf("Please input array a seperated with blank:\n"); for(i=0;i<10;i++) scanf("%d",&a[i]); sort(a,10); printf("After sorting, array a is:\n"); printf("%d ",a[i]); printf("\n"); }
34
传地址方式 传地址方式是在实参和形参之间传递数据的一种方式.
传地址方式所传递的是地址。调用函数时,将实参的地址赋予对应的形参作为其地址.由于形参和实参地址相同,即它们指向同一个内存地址,所以如果被调函数对这个内存地址中保存的数据进行修改,这种修改在主调函数中看得见。 其特点是“参数值的双向传递”
35
传值和传地址 值传递的是数值;地址传递的是地址值
值传递方式是将实际参数的值传递给对应的形式参数,形式参数应分配内存单元,数据传递是单向的,只能从主调函数向被调函数传递。被调函数对形参的修改,不会影响主调函数中的实参值。通常的变量作参数或数组元素作参数都是值传递。 地址传递方式是将实际参数的地址值传递给对应的形式参数。这时为形式参数分配的内存仅用来存放这个地址变量。接受地址值的形式参数一般是指针变量或数组。实际参数可以是变量的地址、数组名或指针变量
36
传值和传地址
37
特殊的数组——字符数组 字符数组是存放字符型数据的数组,每个数组元素中存放的是单个字符 字符数组的定义,如: 字符型也可用整型定义 o k
char c[2], string[5][10]; c[0]='o';c[1]='k'; 字符型也可用整型定义 int c[2], string[5][10]; c[0] c[1] o k
38
字符数组的初始化 如: char c[5]={'H', 'E', 'L', 'L', 'O'};
把5个字符分别赋给c[0],c[1],c[2],c[3],c[4] 字符个数大于字符长度,则出错 字符个数小于字符长度,则后自动补'\0' 如: char c[7]={'H', 'E', 'L', 'L', 'O'}; 给全部数组元素赋初值时可省略数组长度 如: char c[ ]={'o', 'k'}; H E L L O \0 \0
39
字符数组的引用 例6.10 输出一个字符串 #include<stdio.h> void main() {
char c[10]={'I',' ','a','m',' ','a',' ','b','o','y'}; int i; for(i=0;i<10;i++) printf("%c",c[i]); printf("\n"); } 运行结果: I am a boy
40
例6.11输出一个钻石图形 运行结果: * * * * * #include<stdio.h> void main( ) {
char diamond[ ][5]={{' ',' ','*'},{' ','*',' ','*'}, {'*',' ',' ',' ','*'},{' ','*',' ','*'},{' ',' ','*'}}; int i,j; for(i=0;i<5;i++) for(j=0;j<5;j++) printf("%c",diamond[i][j]); printf("\n"); } 运行结果: * * * * *
41
字符串和字符串结束标志 字符串是C语言的一种数据类型, 由若干个字符组成的,最后一个字符是字符串结束标记'\0' 。可以使用一维字符数组存放一个字符串。二维字符数组则可以存放多个字符串。 有了结束标志'\0'后,字符数组的长度就显得不那么重要了,在程序中是依靠检查'\0'的位置来判定字符串是否结束。 系统对字符串常量会自动加一个'\0'作为结束符 printf("hello!\n");
42
字符数组的初始化 char c[ ]={“hello”};或char c[ ]=“hello”;
字符数组并不要求它的最后一个字符为'\0',但由于系统对字符串常量自动加了'\0',而且很多处理都利用了'\0',所以通常我们对字符数组也加上末尾的'\0'。
43
字符数组的输入输出 C h i n a \0 逐个字符输入输出(使用%c) 将整个字符串一次输入输出(使用%s) void main( )
{char c[10]={'I',' ','a','m',' ','a',' ','b','o','y'}; int i; for(i=0;i<10;i++) printf("%c",c[i]); printf("\n"); } 将整个字符串一次输入输出(使用%s) char c[ ]="China"; printf(“%s”,c); 注: 输出时系统遇结束符'\0'就停止,输出结果为China 输出字符不包括结束符'\0' 用'%s'输出字符串时,输出项对应的是数组名 C h i n a \0
44
C h i n a \0 \0 C h i n a \0 C h i n \0 a 如果数组长度大于字符串实际长度,也只输出到'\0'结束
如: char c[10]="China"; printf("%s",c); 输出结果:China 一个字符数组中若包含一个以上'\0',则遇第一个'\0'时输出就结束 可以用scanf函数输入字符串 scanf("%s",c); 键入:China 系统会自动添加末尾的'\0' C h i n a \0 \0 C h i n a \0 C h i n \0 a
45
用scanf函数输入多个字符串 输入数据:How are you? 讨论: 输入数据: How are you? a r e \0 \0
char str1[5],str2[5],str3[5]; scnaf("%s%s%s",str1,str2,str3); 输入数据:How are you? 讨论: char str[13]; scanf("%s",str); 输入数据: How are you? a r e \0 \0 H o w \0 \0 y o u ? \0 H o w \0
46
注意: 输入项为数组名时,不要加地址符号&
char str[13]; scanf("%s",&str); 体会以下两个语句的差别 char c[]="hello"; printf("%o",c); printf("%s",c);
47
字符串处理函数 为了简化程序方便使用,C语言编译系统提供了丰富的字符串处理函数,可直接调用 字符串输出函数 puts(字符数组名)
[参数] 字符数组名 [功能] 输出字符串到终端,并以回车换行作为结束 例: char str[ ]="China\nBeijing"; puts(str); 等价于 printf(“%s\n”,str); 结果:China Beijing
48
字符串输入函数 gets(字符数组名) [参数] 字符数组名 [功能] 从键盘接受一个字符串 [返回值] 字符数组的首地址 例:gets(str); 输入:computer
49
字符串连接函数 strcat(字符数组1,字符数组2) [参数] 字符数组1 长度足够大 字符数组2 字符串常量或字符数组名 [功能] 连接两个字符串,取消第一个字符串结 束标志 [返回值] 字符数组1的首地址 例:char str1[30]=“People's Republic of ”; char str2[ ]=“China”; puts(strcat(str1,str2)); 结果: People's Republic of China
50
字符串复制函数 strcpy(字符数组1,字符串2) [参数] 字符数组1 保存字符串的数组名 字符串2 字符串常量或已存放字符串的字符 数组名 [功能] 将整个“字符串2”复制到字符数组1中 例: char str1[10],str2[ ]="China"; strcpy(str1,str2); 将str2中的6个字符复制到str1中。 思考:能否使用 str1=str2? strncpy(str1,str2,n)函数 [功能]将一个字符串str2中的前n个字符复制给字符串str1
51
字符串比较函数 strcmp(字符串1,字符串2) [参数] 字符串1、字符串2已存放字符串的字符数组 名或字符串常量 [功能] “字符串1”<“字符串2”,函数值为小于0的整数; “字符串1”=“字符串2”,函数值为0; “字符串1”>“字符串2”,函数值为大于0的整数 [返回值] 带符号的整数
52
比较规则: 两个字符串从左到右逐个字符相比(按ASCII 码值大小比较),直到出现不同的字符或遇到 '\0'为止。如全部字符相同,则认为相等;若 出现不相同的字符,则以第一个不相同的字 符的比较结果为准 如:“A”小于“B”,“a”大于“A”,“computer”大于“compare” 如: if(strcmp(str1,str2)==0) printf(“yes”); 思考:能否写成 if(str1==str2) printf(“yes”) ?
53
测试字符串长度函数 strlen(字符串) [功能] 输出字符串的长度(除\0之外) 字符串中小写字母改大写字母函数 [调用格式] strupr(字符串) [功能] 将字符串中所有小写字母换成大写字母 字符串中大写字母改小写字母函数 [调用格式] strlwr(字符串) [功能] 将字符串中所有大写字母换成小写字母
54
例6.12 字符数组应用举例 #include <stdio.h> #include <string.h>
void main() { char a[40],b[80]; gets(a); strcpy(b,a); strupr(b); /*小转大*/ strcat(b,a); /*连接*/ if(strcmp(a,b)<0) printf("a<b\n"); else if (strcmp(a,b)>0)printf("a>b\n"); else printf("a=b\n"); printf("length of a(%s)=%d\n",a,strlen(a)); printf("length of b(%s)=%d\n",b,strlen(b)); puts(a); puts(b); } 运行时输入:China
55
运行结果: a>b length of a(China)=5 length of b(CHINAChina)=10 China CHINAChina
56
作业题 输入一行字符,统计其中有多少个单词,单词之间用一个或多个空格分隔开。 例如运行时输入:I am a boy.
运行结果:There are 4 words in the line. 用一个数组存放班上45个同学的学号或者电话号码(可虚构),编写一个抽奖的软件。 要求:按下回车键屏幕上开始快速滚动;再次按下回车键停止滚动,所显示的号码就是中奖号。 用一个函数实现数组n个数的冒泡排序。 用一个函数实现数组n个数的选择排序。
Similar presentations