1、高级语言程序设计,第七章 数组(Arrays),本章主要内容,数组(概述/定义/引用) 与数值数组有关的常用算法 排序:起泡法/选择法/插入法查找:顺序查找法/折半查找法矩阵运算 字符数组和字符串 与字符数组有关的常用算法,复习,C的数据类型: 基本类(简单类)字符型/整型/实型/枚举型构造类(组合类)数组/结构体/共用体指针类空类型(void),一、概述,对于变量 基本类型单个出现的变量,每个变量可以代表一个确定的数据(变量值),且具有一定属性。如 int x,y; 但变量间不存在确定的相互关系。构造类型由基本类型按一定规则组成。其中:数组:由一组有序数据(数组元素)组成。每个元素:有相同类
2、型,统一数组名;用下标(index)确定其顺序;但可以各自取值。如 int a5;其中: 表示a是个数组,而不是一个简单变量a。 5表示该数组共有5个元素,元素编号从0开始,a0表示第1个元素,a4表示第5个元素(最后一个),一、概述,数组的用处很多。简单例子:要读入某班全体50位同学某科学习成绩,然后进行简单处理(求平均成绩、最高分、最低分) 若用简单变量,需50个不同变量名,要用很多个scanf命令。如 int score1,score2,score50;scanf(“%d,%d,%d”,示例程序如下:,#define NUM 50main()int i,scoreNUM,highest;
3、float sum=0,average;clrscr();/*依次读入全班同学分数*/ for (i=0;iNUM;i+) printf(“请输入第%d位同学的成绩:“,i+1);scanf(“%d“, ,/*求平均成绩并显示出来*/for (i=0;ihighest) highest=scorei;printf(“n最高分是:%dn“,highest); ,二、数组的定义,同变量一样,数组也必须“先定义,后使用”。 定义内容: 数组名(同变量名:字母、下划线、数字;字母或下划线开头;长度32)类型(存储属性/数据类型)大小(维数/元素个数) 定义的一般形式:存储属性 数据类型 数组名常量表达
4、式常量表达式注意:数组长度必须是常量表达式常量或符号常量,其值必须为正,不能为变量。,数组长度 (数组元素最大个数),二、数组的定义,错误: int n=5; int an;,正确: #define N 5 int aN;,正确:int a10,b54;char name8,ch23;static float x8*2+1,table234;#define NUM 40;int aNUM,bNUM+2;,一维数组和多维数组,一维数组用一个下标来确定各元素在数组中的顺序。可用排列成一行的元素组来表示。如 int a5; (右上图) 二维数组用两个下标来确定各元素在数组中的顺序。可用排列成ij列的
5、元素组来表示。如 int b23; (右下图) n维数组用n个下标来确定各元素在数组中的顺序。如 int c324;n3时,维数组无法在平面上表示其各元素的位置。,n维数组的元素总数等于各维长度之积。,特别注意 数组名表示每个数组的首地址,即: a 表示 &a0b 表示 &b00,more about multidimensional arrays,为了便于理解,可以把多维数组看成一维数组的扩展: 二维数组(nm)可以看成n行m个元素的一维数组; 三维数组(pnm)可以看成p页n行m个元素的一维数组,即p页二维数组(nm); 四维数组(vpnm)可以看成v册p页n行m个元素的一维数组,即v册三
6、维数组(pnm) 以此类推。,三、数组的存储结构,根据数组的数据类型,为每一元素安排相同长度的存储单元。 根据数组的存储属性,将其安排在内存动态、静态存储区或寄存器区。,四、数组的初始化(赋初值),一般形式:int a5=1,2,3,4,5;int b23=1,2,3,4,5,6;或int b23=1,2,3,4,5,6; 【演示】设置watch,观看下列数组初值情况:int a23; int c23=1,2;,四、数组的初始化(赋初值),简略形式: 1、省略第一维数组大小。如:int a =,b 3=;例:int a =3,4,5,b 3=1,3,4,5,6,4;2、省略元素值。如:int
7、x6=1,2,3,4; (x4、x5自动用0补足) 3、全部元素初始 化为0int a5=0; int b32=0;,四、数组的初始化(赋初值),【例一】以下程序的运行结果是什么? main() int a3=1,2,3,4,5,6,0;printf(“%d,%d,%dn“,a11,a21,a31); ,1 2 3 4 5 0 6 0 0 0 0 0,结果:5, 0, 0,【例二】若int a 3=1,2,3,4,5,6,7,则a数组的第一维大小是多少?,1 2 3 4 5 6 7 0 0,说明:静态/外部数组未初始化,默认初值是0(数值)或空格(字符)auto数组未初始化,初值为某个随机数。
8、,五、数组的引用(使用数组元素),原则:先定义后引用 引用形式: 数组名下标 只能逐个引用数组元素,不能一次引用整个数组。 引用数组元素要注意下标不要出界(编译程序不检查是否“出界”)。 每个数组元素均可按一个简单变量的方式进行处理(如参加运算、赋值等)。,五、数组的引用(使用数组元素),(设已有定义int a26,x,y ,i=0,j=0;)a23=4; /*下标为常量*/ scanf(“%d”, /*下标为一个复杂的整型表达式*/错误: a2,3=1,调试时,可将数组名或数组元素名设置为watch进行跟踪.,讨论: 如果下标值小于0或超过数组长度时会出现什么情况?,例: main()int
9、 a=1,b5,c=2,i;for (i=0;i=5;i+)bi=i+1;,运行程序或单步执行观察变量变化情况可以看到,变量c的值因数组越界而被悄悄破坏了(可能产生严重的错误后果!) Lt7_4.c,1,2,3,4,5,6,0,1,2,3,4,5,6,数组常用的循环形式,法一 int i,a100; for(i=0;i100;i+)ai=i;,法二 int i,a100; for(i=0;i=99;i+)ai=i;,C程序中常用的是第一种方法。注意在此法中,循环变量的终值是“小于”而非“等于”数组长度!否则将导致“越界”的发生。,如何使两个数组的值相等:,/*错误编程*/ main() int
10、 a4=1,2,3,4,b4;b=a; ,解决方法 法1:逐个元素赋值b0=a0;b1=a1;b2=a2;b3=a3; 法2:通过循环赋值int i;for (i=0;i4;i+)bi=ai;,原因: 数组名表示数组的首地址,其值不可改变!,应用示例: 下列程序的功能是显示如下图形,请填空。,1 0 0 0 0 2 1 0 0 0 3 2 1 0 0 4 3 2 1 0 5 4 3 2 1,main() int a55,i,j;clrscr();for (i=0;i5;i+) for (j=0;j5;j+) if ( 【1】 ) aij=0;else aij=【2】;printf(“%3d“,
11、aij);printf(“n“); ,a55分析: a00 a01 a02 a03 a04 a10 a11 a12 a13 a14 a20 a21 a22 a23 a24 a30 a31 a32 a33 a34 a40 a41 a42 a43 a44,ij,i+1-j,【分析】这类题的元素值排列很有规律,所以一般要从分析行数 i、列数 j与元素值的关系着手。分析下图可知,当 i=j时,元素值随行数 i 增加而增加,随列数 j 增加而减小,这样就很容易得出其元素值与 i,j 的关系是 i+1-j。,【例一】以下程序的功能是什么?,#include main()int i;float sum=0,
12、x10;float mean(float,int);clrscr();for(i=0;i10;i+)printf(“请输入x%d=“,i);scanf(“%f“,float mean(float a, int i)if (a0) printf(“%f的平方根是:%fn“,a,sqrt(a);return sqrt(a);elseprintf(“x%d=%fn“,i,a);return 0.0;,在主函数中输入10个数值,并调用功能函数求其正数的算术平方根之和。,七、与数值数组有关的常用算法,排序:起泡法/选择法/插入法 查找:顺序查找法/折半查找法 矩阵运算1、常用排序算法 起泡法(冒泡法/气
13、泡法)有n个杂乱无序的数,要求将这n个数从小到大(或从大到小)排序后输出。,【例一】排序原理示意如下(n=5):,排序前第1轮(i=1)第2轮(i=2)第3轮(i=3)第4轮(i=4),共需进行n-1 =4轮; 从第1个开始,两两比较,大者交换到后面(右边); 每轮从第1个比到第n-i个。,这种排序方法之所以叫“冒泡法”,是因为在排序过程中,较小的数象气泡一样逐渐往前冒(向上冒),大的数逐渐向后沉,最终完成排序。,流程图和程序如下:,#define N 5 main() int i,j,t,aN+1;for (i=1;iaj+1) t=aj;aj=aj+1;aj+1=t;for (i=1;i=
14、N;i+)printf(“%d “,ai); ,选择法,从算法优化的角度对“冒泡法”进行改进。 冒泡法每一轮都要将数组中的数两两比较,并根据大小交换之效率低。 选择法改进处:两两比较后并不马上交换,而是找到最小数后记下其下标。在一轮比较完毕后,再将最小的数一次交换到位。比较次数不变,交换次数减少。,流程图和程序如下:,法1:从左到右依次从小到大排放 #define N 5 main() int i,j,t, ,p aN+1 =0,5,10,-7,3,7;for (i=1;iaj) p=j; if(p!=i) t=ap;ap=ai; ai=t; for (i=1;i=N;i+)printf(“%
15、d “,ai);printf(“n“); ,流程图和程序如下:,法2:从右到左依次从大到小排放 #define N 5 main() int i,j,t,p,aN+1=0,5,10,-7,3,7;for (i=1;iap) p=j; if(p!=N-i+1)t=ap;ap=aN-i+1;aN-i+1=t;for (i=1;i=N;i+)printf(“%d,“,ai);printf(“n“); ,插入法,main() int a5=4,7,2,5,8;int i,j,m;for (i=1;i=0 ,如果有N个元素,也是要比较N-1轮,但每轮取第i个(i从1开始)元素的值为暂存值m,然后与左边的
16、各数(从j=i-1开始)比较一直到左边第一个(j=0)为止。如果m比左边大,就让左边的值右移,最后将该轮的第i个数插到左边的合适位置(如果它比较大的话)。,【讨论】如果要求升序(结果为24578)呢?,while (j=0&maj),插入法演示:,初始值:4 7 2 5 8 第一轮(i=1,m=a1,j=0)比较一次,移动一次,交换一次 7 4 2 5 8 第二轮(i=2,m=a2,j=1)由于maj,没有比较, 第三轮(i=3,m=a3,j=2) 7 4 2 2 8 7 4 4 2 8 7 5 4 2 8 第四轮(i=4,m=a4,j=3) 7 5 4 2 2 7 5 4 4 2 7 5 5
17、 4 2 7 7 5 4 2 8 7 4 4 2,2.查找,main() int a8=25,57,48,37,12,92,86,33;int i,x;clrscr( );printf(“请输入要查找的数 x=“);scanf(“%d“, ,顺序查找法,【例一】,2.查找,main() int a9=25,57,48,37,12,92,86,33;int i,x;printf(“请输入要查找的数 x=“);scanf(“%d“, ,顺序查找法,【例二】快速顺序查找法,讨论: 为什么数组长度要设为9? 为什么要用a8=x? 去掉a8=x行不行?,折半查找法,前提:数据已按一定规律(升或降序)排列
18、好。 思路:先检索当中的一个数据是否所需,如不是,判断要找的数据在哪一边,缩小范围后再按同样方法继续检索,直到找到或找遍。 算法:设要找的数为x,n+1个数据已排好序存放在数组a中。设low=0,high=nmid=(low+high)/2if (x=amid) 找到了;else if (xamid) 说明x在右边,让low=mid+1;else 说明x在左边,让high=mid-1,重复b和c两步操作,直到x=mid(找到)或lowhigh(找遍了)为止。,main() int a9=6,12,18,42,44,52,67,94,99;int low=0,mid,high=8,x;clrsc
19、r();printf(“请输入要查找的数 x=“);scanf(“%d“, ,3、矩阵运算,【例一】有一34矩阵,编程求其元素最大值并输出其行、列号。,main() int i,j,x,y,max;int a4=3,5,8,1,6,9,7,12,-6;max=a00;for (i=0;imax) max=aij;x=i;y=j;printf(“max is a%d%d=%dn“,x,y,max); ,3 5 8 16 9 7 12 -6 0 0 0,要点:用两重循环遍历所有元素。,【讨论】如果求最小值?,【例二】求矩阵a、b乘积,结果存入矩阵c中并按矩阵形式输出。,【说明】矩阵相乘的规则:一个
20、mp矩阵A=(aij),可以右乘一个pn矩阵B(bij),得到一个mn矩阵C(cij),其中(i=1,2,m,j=1,2,n) :,main() int a32=2,-1,-4,0,3,1;int b22=7,-9,-8,10;int i,j,k,s,c32;for(i=0;i3;i+)for(j=0;j2;j+)for(k=s=0;k2;k+)s+=aik*bkj;cij=s;for(i=0;i3;i+) for(j=0;j2;j+)printf(“%6d“,cij);printf(“n“); ,八、字符数组和字符串,【字符数组】存放字符(每个数组元素存放一个字符),1、字符数组的定义 如:
21、 char a10; char a23;,字符数组各个元素分别存放一个字符的数组。 字 符 串 “” (字符串常量)以“0”结尾。实际使用中,可以将字符串看成是特殊的字符数组(以“0”为最后一个元素值)。如字符串”ab12”可以看成:int a5=x,y,1,2,0;,2、字符数组的初始化,单字符方式 char a10=A, B, C, D;char b23= A, B, C, D, E,F;【注意】如果初值个数小于数组长度,则多余的数组元素自动为空字符(0) 字符串方式 char a5=“ABCD”; char c =”ABCD”;char a25=A,B,C,0,x,y,0;char a2
22、5=“ABC”,”XY”;二维字符数组可以认为由若干个一维字符数组(字符串)组成。,示例,【例一】比较以下字符数组长度是否相同: char a =”ABCD”; char b = “ABCD”; char c =A,B,C,D; 【例二】下列程序段的运行结果是: char a5=a,b, 0,d,0;printf(“%s”,a);,如果 printf(“%s”,a+1);结果是?,说明:%s的作用是输出一个字符串,直到遇到0为止。,注意: 在二维数组中,双下标引用表示某行某列的某个元素 单下标引用表示某行的字符串,【例三】分析以下程序的运行结果: main() char word310;int
23、 i;for (i=0;i3;i+)scanf(“%s“,wordi);printf(“%s“,wordi-2); ,运行时,输入: 12345 abcdef ABCDEFG,wordi表示第i+1行word元素首地址(二维数组用单下标表示某行的字符串),结果:abcdef,3、字符数组的输入(赋值),如果定义有 char a10; 除了直接在定义时初始化,定义后赋值的方法有:法1:逐个元素赋值 a0=A,a1=X;法2:循环+scanf(“%c”, ,字符数组的输入(赋值),法3:scanf(“%s”, 字符数组名); 用于从键盘接收不带空格的字符串。如:scanf(“%s”,a); /*数
24、组名前不可加&号*/此法可自动在所输入的字符串末尾加上0。但输入的字符串中不能有空格。(C语言规定scanf用%s时,以空格或回车符作为字符串的间隔符。所以,上例中,如果从键盘输入“Computer”然后回车,则数组a存放的是”Computer0”。如果输入“Turbo C“,数组a中实际只存放”Turbo0”)。 法4:gets(字符数组名); 用于从键盘接收一个任意字符串。gets(a)执行时,将一直读取用户从键盘输入的所有字符,直到遇到回车符(n)为止。成功返回数组a首地址,否则返回NULL。gets(a)亦会自动在字符串末尾加上0(代替n)。,示例,main() char name20
25、;printf(“Whats your name? “);gets(name);printf(“Hi,%s,nice to meet you!n“,name);运行程序时,从键盘输入:XXX (XXX为学生姓名),结果:Hi,XXX ,nice to meet you! (XXX为学生姓名),示例,main() char a10;gets(a);printf(“%sn“,a+2); 运行程序时,从键盘输入:abc defg,结果:c defg,4、字符数组的输出,法1:逐个元素输出 循环+printf(“%c”,); 法2:字符串输出 printf(“%s”,字符数组名); 法3:字符串输出
26、puts(字符数组名);将一个以NULL(0)结尾的字符串输出到屏幕上,并自动换行。,示例,已知函数isaplha(ch)的功能是判断自变量ch是否为字母,若是,该函数值为1,否则为0。以下程序的输出结果是 。 #include #include void fun(char str ) int i,j;for (i=0,j=0;stri;i+)if (!isalpha(stri) strj+=stri;strj=0; main() char str100=“Current date is Sat 12-30-2000.“;clrscr();fun(str);printf(“%sn“,str);
27、 ,结果: 12-30-2000,示例讨论,常用si 作循环条件,当循环(i递增)到字符串结束处(0)便自动结束循环。 典型结构:如果s是字符串,则下列结构可以将s中不符合 条件的字符删去。int i,j;for (i=0,j=0;stri;i+) if (条件) strj+=stri;strj=0; 思考:如果上题中去掉if (!isalpha(stri)中的!号,结果是什么? 如果将isalpha()函数改为islower、isupper、isdigit,结果是什么? (教材P383-384),(CurrentdateisSat),(urrentdateisat、CS、12302000),
28、5、字符串运算函数,gets( )和puts( ) 字符串输入/输出函数 strcpy( ) 字符串考贝函数(包含在string.h中,下同)形式:strcpy(目的字符数组,源字符串);作用:将源字符串考贝到目的字符数组中,直到遇到源字符串的终止符0为止。函数返回值:目的字符数组的地址。注意:目的字符数组要定义得足够大。,若要将一个字符串常量或从某一首地址开始的字符串复制给别的数组,只能用本函数或指针。,示例,main( ) char a =“abcde“;char b10;b=“abcde“; b=a; ,/*编译出错*/,/*编译出错*/,【讨论】编译出错原因何在?,a,b都是两个数组定
29、义时分配的内存存储单元首地址,是个常量,不能改变(不能赋值)。,示例,#include “string.h” main( ) char s10,sp =”HELLO”;strcpy(s,sp);s0=h;s6=!;puts(s); ,结果: hELLO,【讨论】 结果为什么不是:hELLO! 如果让s5=!,结果又会如何?,如果只需考贝字符串的一部分,如果是考贝字符串的一部分,可用函数 strncpy(目的字符数组,源字符串,考贝字符数),#include “string.h” main( ) char s =”This is a source string.”, b20;strncpy(b,
30、s,16);b16=0;printf(“%sn”,b); ,结果:This is a source,more string functions,strcat( ) 字符串连接函数形式:strcat(目的字符数组,源字符串);作用:将源字符串连接到目的字符数组后面。函数返回值:目的字符数组的地址。注意:目的字符数组要定义得足够大。,示例,#include “string.h“ main() char a =“abcde“;char b =“12345“;strcat(b,a);printf(“%s,%sn“,a,b); ,结果: abcde,12345abcde,数组b长度定义不够,将数组b的长
31、度定义11,则出错消失?,【讨论】 为什么程序执行完后出错?,示例,#include “string.h“ main() char a80=”AB”,b80=”LMNP”;int i=0;strcat(a,b);while (ai+!=0) bi=ai; puts(b); ,结果:LBLMNP,【注意】bi=ai是从i=1开始,more string functions,strcmp( ) 字符串比较函数形式:strcmp(字符串1,字符串2);作用:对两个字符串从各自第一个字符开始进行逐一比较,直到对应字符不相同或到达串尾为止。函数返回值:确定了比较结果小于0 字符串1小于字符串2等于0 字
32、符串1等于字符串2大于0 字符串1大于字符串2,示例,#include main() int i;char str10,temp10=“Control“;for ( i=0; i4; i+)gets(str);if(strcmp(temp,str)0) strcpy(temp,str); puts(temp); ,结果:PAGE,从键盘输入: BOOK CUT GAME PAGE,more string functions,strlen( ) 字符串长度函数形式:strlen(字符串)作用:测试所给字符串的实际字符个数(不包括0)函数返回值:实际字符个数,以下程序段的运行结果是什么? char
33、 a =”tr0willn”; printf(“%d,%d”,sizeof(a),strlen(a);,结果:10,3,more string functions,strupr( )和strlwr( ) 大小写转换函数strupr(字符串) 小写大写strlwr(字符串) 大写小写,#include main() char s50;clrscr();printf(“Input the string of lower case:“);gets(s);strupr(s);printf(“The string after strupr is:%sn“,s); ,例题:编写一个程序将用户输入的一个字符
34、串转换成整数。,main() char s50; int n,I,sign; printf(“enter a string:n”); scanf(“%s”,s); sign=1;I=0; If(sI=+ | sI=-)sign=(sI+=+)?1:-1; for(n=0;sI=0,gets(s); for(I=0;aI= |ai=t;I+); sign=1;,例题:有一行字符,要求将每个单词中的第一个字母改为大写字母(本身大写则不变),#include main() char str225;int I=0; printf(“input a string(English):n”); while(strI+=getchar()!=n); strI-1=0; for(I=0;strI!=0;I+)if(strI-1= |I=0),例题:从键盘输入一个字符串和一个要删除的字符,然后输出删除字符后的字符串。,#include main() char str20,d;int I=0; printf(“input a string:n”); while(strI=getchar()!=n) I+; strI=0; printf(“input a deleted char:n”); scanf(“%c”,