1、第九章第九章数数 组组(一一)第1页,共42页。回顾指针回顾指针2.int*p,*a,b=10;p=&a;a=&b;&a&bb10pa第2页,共42页。真题:真题:1.有以下程序:有以下程序:#include main()int n,*p=NULL;*p=&n;printf(“input n:”);scanf(“%d”,&p);printf(“output n:”);printf(“%dn”,p);该程序想通过指针该程序想通过指针p为变量为变量n读入数据并输出,但有多处错误。以读入数据并输出,但有多处错误。以下语句正确的是下语句正确的是;A int n,*p=NULL;B *p=&n;C sc
2、anf(“%d”,&p);D printf(“%dn”,p);第3页,共42页。思考:用变量存储一系列数据,如学号?用int i=001,j=002,h=003.w=024?如何简化解决,开辟一系列空间用变量可以连续存放一系列数据或字符第4页,共42页。为什么要使用数组3-3数组内存内存12065984数组的元素容器中保存的物品日常生活中的容器日常生活中的容器程序中的数组程序中的数组第5页,共42页。声明一维数组数据类型数据类型 数组名数组名size;类型说明符int、char、float 数组名常量表达式:数组大小int num50;char list 20;double pressure_
3、level6;#define LIMIT 20.int emp_codesLIMIT;第6页,共42页。int a8;1.int 是类型名,只能存放整型是类型名,只能存放整型2.a是数组名是数组名3.数组数组a中有中有8个元素,分别为个元素,分别为a0,a1a7.即即下标从下标从0开始开始4.执行完此语句的结果是:为数组执行完此语句的结果是:为数组a分配分配8个连续的单元,每个单元占个连续的单元,每个单元占4个个字节字节理解:数组理解:数组a中有中有8个变量,变量名称依次为个变量,变量名称依次为a0,a1a7.第7页,共42页。内存内存a0a1a2a3a4146899.1.3初始化一维数组in
4、t a5=1,4,6,8,9;相当于:相当于:a0=1;a1=4.说明:说明:1.int a5=1 合法,没有初始化的变合法,没有初始化的变 量量a1-a4自动赋初值为自动赋初值为02.int a5=1,4,6,8,9,3;不合法不合法即:数组的大小即:数组的大小=元素的个数元素的个数a其他的初始化情况:其他的初始化情况:int arr10=10,9,8,7,6,5,4,3,2,1,0;/错误!越界了错误!越界了 int arr10=9,8,7,5;/正确,后面的正确,后面的6个元素未初始化个元素未初始化 9.1.4 通过赋初值定义数组的大小通过赋初值定义数组的大小int arr=9,8,7;
5、/正确:元素个数为正确:元素个数为 3(思考)(思考)int arr=;/错误,到底是几个元素?错误,到底是几个元素?第8页,共42页。内存内存为一维数组动态赋值为一维数组动态赋值float price4;printf(“Enter prices of 4 booksn”);for(i=0;i=3;i+)scanf(“%f”,&pricei);price0price1price2price3price12.341002.1017.511.12第9页,共42页。问题描述:求一组数中的最大值和最小值。数组应用1void main()int num5,max,min,i;printf(请输入5个数:
6、n);for(i=0;i5;i+)scanf(%d,&numi);max=num0;min=num0;for(i=1;i5;i+)if(maxnumi)min=numi;printf(n最大值为:%d,max);printf(n最小值为:%dn,min);读入5个值保存在数组中求最大值和最小值演示学生用书示例3第10页,共42页。问题描述:输入10个数,保存在一个数组中,在数组中查找某个数,给出是否找到的信息。如果找到了,要求输出该数在数组中所处的位置;如果找不到,输出“没有找到!”。数组应用2#define N 10for(i=0;iN;i+)scanf(%d,&numi);printf(n
7、 请输入要查找的数:);scanf(%d,&search);for(i=0;iN;i+)if(numi=search)break;if(iN)printf(n 在数组的第%d 个位置找到了数字%d!n,i+1,search);else printf(n 没有找到!n);读入10个值保存在数组中在数组中查找,一旦找到,通过break语句跳出循环演示学生用书示例4第11页,共42页。一维数组和指针一维数组和指针 回顾指针:存放一个变量地址的变量(指回顾指针:存放一个变量地址的变量(指向一个变量)向一个变量)ip例如:例如:int*p,i=4,j;p=&i;j=*p第12页,共42页。9.2一维数组
8、和指针C语言中,数组名可以认为是一个存放地址值的指针变量名,语言中,数组名可以认为是一个存放地址值的指针变量名,其中的地址值是数组第一个元素的地址。其中的地址值是数组第一个元素的地址。例如:例如:int a2;数组名;数组名a可以认为是一个指针变量名,存的是数组的可以认为是一个指针变量名,存的是数组的第一个元素第一个元素a0的值的值注意:注意:float a10,*p,x;a=&x;/不合法不合法,声明一个数组的同时,声明一个数组的同时,a中就确定了中就确定了 永远指向永远指向a数组的首地址数组的首地址 a+;不合法不合法第13页,共42页。在数组中给指针赋初值:在数组中给指针赋初值:int*
9、p,a2;p=&a0;合法合法 p=a;合法;合法通过指针从终端读入数据;通过指针从终端读入数据;for(p=a,k=0;k10;k+)scanf(“%d”,p),p+;通过数组从终端读入数据通过数组从终端读入数据;for(k=0;k10;k+)scanf(“%d”,&ak)功能相同,都是使指针变量功能相同,都是使指针变量p指向指向a数组的首地址数组的首地址a0a1a2a3a4.p第14页,共42页。9.2.3通过通过数组的首地址数组的首地址引用数组元素引用数组元素1.int a7;a相当于是指针变量,是数组元素的首地址。相当于是指针变量,是数组元素的首地址。则:则:a值相当于值相当于&a0
10、a+1相当于相当于&a1 思考:思考:*a,*(a+1)代表什么呢?)代表什么呢?*&a0,*&a1代表什么呢?代表什么呢?故:故:*a和和*&a0即为即为 a0 *(a+1)和)和*&a1即为即为a1 *(a+k)和)和*&ak即为即为ak 第15页,共42页。9.2.3通过通过指针指针引用数组元素引用数组元素1.int a7,*p;p=a;p=&a0;则:对于数组元素则:对于数组元素a0,可以用可以用*p引用;引用;a1可以用可以用*(p+1)引用,引用,ak可以用可以用*(p+k)引用引用 第16页,共42页。int*p,s10,i;p=s;总结:总结:表示数组表示数组s中的第中的第i个
11、元素:个元素:si,*(p+i),*(s+i),*&si,pi 表示数组表示数组s中的第中的第i个元素地址个元素地址:&si,p+i,s+i,注意:注意:虽然数组名虽然数组名s可以看做一个指针变量,但是可以看做一个指针变量,但是s是不可变的,而是不可变的,而p是可变的。即是可变的。即s+,s=p都是不合法的都是不合法的第17页,共42页。例例 int a=1,2,3,4,5,6,7,8,9,10,*p=a,i;数组元素地址的正确表示:数组元素地址的正确表示:(A)&(a+1)(B)a+(C)&p (D)&pi 数组名是数组名是地址常量地址常量p+,p-()a+,a-()a+1,*(a+2)()
12、第18页,共42页。例:输出数组中的全部元素 有三种方法:(1)main()int a10;int i;for(i=0;i10;i+)scanf(“%d”,&ai);printf(“n”);for(i=0;i10;i+)printf(“%d”,ai);2)main()int a10;int i;for(i=0;i10;i+)scanf(“%d”,&ai);printf(“n”);for(i=0;i10;i+)printf(“%d”,*(a+i);3)main()int a10;int*p,i;for(i=0;i10;i+)scanf(“%d”,&ai);printf(“n”);for(p=a;
13、p(a+10);p+)printf(“%d”,*p);第19页,共42页。9.3函数之间对一维数组和数组元素的引用函数之间对一维数组和数组元素的引用1、数组元素作实参、数组元素作实参 当调用函数时,数组元素可以作为实参传送给形参,和普通变量一样,当调用函数时,数组元素可以作为实参传送给形参,和普通变量一样,即即传值调用传值调用。形参的改变不会影响实参的值。形参的改变不会影响实参的值2、数组名作实参、数组名作实参 数组名也可以作为实参传送,数组名本身是一个地址值,因此是数组名也可以作为实参传送,数组名本身是一个地址值,因此是地地址值的传递址值的传递。形参的改变会影响实参的值。形参的改变会影响实参
14、的值第20页,共42页。例题例题9.2编写程序,通过编写程序,通过一个函数一个函数给主函数中定义的数组输入若给主函数中定义的数组输入若干大约或等于干大约或等于0的整数,用负数作为结束标志;调用的整数,用负数作为结束标志;调用另一个函数另一个函数输输出该数组中的数据。出该数组中的数据。分析:分析:main声明一个数组声明一个数组s;调用一个子函数调用一个子函数1给数组赋值;给数组赋值;调用一个子函数调用一个子函数2输出数组的值输出数组的值子函数子函数1 当大于等于当大于等于0时一直输入;时一直输入;子函数子函数2 依次输出数组元素的值依次输出数组元素的值值传递?地址传递?值传递?地址传递?值传递
15、?地址传递?值传递?地址传递?需要有一个变量,来计算需要有一个变量,来计算输入数据的个数,并返回输入数据的个数,并返回第21页,共42页。#include#define M100void arrout(int*,int)void arrint(int*)main()int sM,k;k=arrin(s);(数组名作为实参)(数组名作为实参)arrout(s,k);int arrin(int*a)int i=0,x;scanf(“%d”.&x);while(x=0)*(a+i)=x;i+;scanf(%d”.&x);return i;当数组名作为实参时,对应的形参除了是指针外,还可以用另外两种形
16、式。当数组名作为实参时,对应的形参除了是指针外,还可以用另外两种形式。上例中的函数调用上例中的函数调用arrin(s);对应的函数首部可以写成以下三种形式:对应的函数首部可以写成以下三种形式:(1)arrin(int*a)(2)arrin(int a)(3)arrin(int aM)第22页,共42页。void arrout(int*a,int n)int i;for(i=0;in;i+)printf(”%4d”,*(a+i);printf(“n”);解释:解释:printf(i+1)%5=0?“%4dn”:“%4d”,*(a+i);使使5个一行输出个一行输出第23页,共42页。数组元素地址作
17、为实参数组元素地址作为实参9.3编写函数,对具有编写函数,对具有10个元素的个元素的char类型数组,从下标为类型数组,从下标为4的的元素开始,全部设置为元素开始,全部设置为*,其余不变,其余不变 假设已知元素分别为假设已知元素分别为ABCDEFGHIJ 思路:定义一个思路:定义一个char类型数组存放元素类型数组存放元素 定义一个指针变量,指向下标为定义一个指针变量,指向下标为4的元素的地址;的元素的地址;通过指针变量的变化,来修改元素为通过指针变量的变化,来修改元素为*输出变化后的元素输出变化后的元素第24页,共42页。#include#define M 10#define B 4,voi
18、d setstar(char*,int);void arrout(char*,int);main()char cM=A,B,C,C,D,E,F,G,H,I,J;setstar(&c4,M-B);arrout(c,M);void setstar(char*a,int n)int I;for(i=0;in;i+)*(a+i)=*;Void arrout(char*a,int n)int i;for(i=0;in;i+)printf(“%c”,ai);传递的是数组元素的地址传递的是数组元素的地址第25页,共42页。应用举例例题例题9.4 定义一个含有定义一个含有15个元素的数组,编写函数:个元素的数
19、组,编写函数:1.调用调用C库函数中的随机函数给所有元素赋以库函数中的随机函数给所有元素赋以0-49的随机数(数组的随机数(数组x)2.输出数组元素中的值输出数组元素中的值3.按顺序对每隔三个数求一个和数,并传回主函数(数组按顺序对每隔三个数求一个和数,并传回主函数(数组w)4.最后输出所有求出的和值最后输出所有求出的和值附:头文件附:头文件stklib.h中随机函数中随机函数 n=rand()%x n可以得到可以得到0 x-1的随机数,所以得到的随机数,所以得到0-49的随机数即用的随机数即用rand()%50第26页,共42页。#include#include#define SIZE 15
20、#define N 3main()int xSIZE,wSIZE/N=0;getrand(x,SIZE);/产生产生15个随机数放入个随机数放入x数组中数组中 priarr(x,SIZE);/输出输出15个随机数个随机数 getave(x,w,SIZE);/每每3个数求一个和,放入个数求一个和,放入w数组数组 priarr(w,SIZE/N);/输出输出5个和数个和数第27页,共42页。例题例题9.5 将数组中的数按倒序重新存放,在操作时,将数组中的数按倒序重新存放,在操作时,只能借助一个只能借助一个临时存储单元而不能另外开辟数组。临时存储单元而不能另外开辟数组。思路:第一个与最后一个借助临时
21、存储单元交换,依次类推思路:第一个与最后一个借助临时存储单元交换,依次类推1020304050607080临时存储单元临时存储单元计数器计数器i计数器计数器j直到直到i=j停止停止第28页,共42页。程序如下:程序如下:#include#define NUM 8void priout(int s,int n)int i;for(i=0;in;i+)printf(%4d”,si);printf(“n”);void invert(int*a,int n)/逆序排列逆序排列int i,j,t;i=0;j=n-1;while(ij)/直到直到i=j时交换结束时交换结束 t=ai;ai=aj;aj=t;
22、/交换过程交换过程 i+;j-;/i向后移动向后移动j向前移动向前移动 main()int aNUM=10,20,.;printf(“输出原始数据:输出原始数据:”);priout(a,NUM);invert(a,NUM);printf(“输出逆序后的据:输出逆序后的据:”);priout(a,NUM);第29页,共42页。例题例题9.6已知整型数组中的值在已知整型数组中的值在0-9范围内,统计每个整数的范围内,统计每个整数的个数。个数。假设一组数:假设一组数:6 4 7 6 1 4 7 9 2 5 6 1 8 1即统计即统计1的个数,的个数,2的个的个数数9个数个数思路:思路:声明数组,输入
23、数组元素(运用随机函数);声明数组,输入数组元素(运用随机函数);对数组进行元素统计,将统计结果存放另一个数组中;对数组进行元素统计,将统计结果存放另一个数组中;输出统计结果;输出统计结果;第30页,共42页。假设已经获得假设已经获得M个数据元素存于数组个数据元素存于数组a中中声明一个数组声明一个数组cN,存放统计结果;存放统计结果;即即c0里存放里存放0的个数,的个数,c1存放存放1的个数的个数相当于相当于c0里存放里存放ai=0时的个数;时的个数;c1存放存放ai=1的的个数个数 for(i=0;iN;i+)ci=0;for(i=0;iM;i+)cai+;6 4 7 6 1 4 7 9 2
24、 5 6 1 8 1c6=1;c4=1;c7=1;c6=2;c4=2;c7=2.第31页,共42页。例题例题9.7.已知存放在已知存放在a数组中的数不相重合,在数组中的数不相重合,在a数组中找出和数组中找出和x值值相同的元素的位置,若找到,则输出该值和值在数组相同的元素的位置,若找到,则输出该值和值在数组a中的位置,中的位置,没找到输出相应的信息。没找到输出相应的信息。思路:思路:1.通过终端设备(键盘)生成数组通过终端设备(键盘)生成数组a 2.输入一个数输入一个数x 3.查找数组查找数组a,是否有与,是否有与x相等的值,有则输出该值相等的值,有则输出该值 和值在数组和值在数组a中的位置,没
25、有输出没找到。中的位置,没有输出没找到。第32页,共42页。1.通过终端设备(键盘)生成数组通过终端设备(键盘)生成数组a int arrin(int*a)int i;n;do printf(“确定输入数组元素的个数:确定输入数组元素的个数:”)scanf(“%d”,&n);while(n=NUM);/确定元素的个数确定元素的个数0&=NUM printf(“开始输入开始输入n个数据个数据“););for(i=0;in;i+)scanf(“%d”,a+i);return n;下标到下标到n,但是只在,但是只在n-1之前放置元素,之前放置元素,对于对于an作为辅助空间作为辅助空间第33页,共42
26、页。3.查找数组查找数组a,是否有与,是否有与x相等的值,有则输出该值相等的值,有则输出该值 和值在和值在数组数组a中的位置,没有输出没找到。中的位置,没有输出没找到。int search(int*a,int x,int n)int i,p;i=0;an=x;/将将x放入辅助空间放入辅助空间 while(x!=ai)i+;if(i=n)p=-1;else p=I;return p;ana0an-1xi第34页,共42页。#defint NUM 30main()int aNUM,x,n,p;n=arrin(a);printf(“输入要查找的元素输入要查找的元素x”););scanf(“%d”,&
27、x););p=search(a,x,n);if(p!=1)printf(“%d 的下标是:的下标是:%d”,x,p);else printf(“没有找到与没有找到与x值一样的元素值一样的元素”););第35页,共42页。获得随机数获得随机数void getrand(int*a,int n)int i;for(i=0;in;i+)ai=ranf()%50;第36页,共42页。输出输出15个随机数个随机数void priarr(int*a,int n)inti i;for(i=0;in;i+)printf(“%5d”,ai);if(i+1)%5=0)printf(“n”);/使每使每5个一行输出个
28、一行输出 printf(“n”);第37页,共42页。每三个求和,放入数组每三个求和,放入数组w中中void getave(int*a,int*b,int n)int i,j,sum;for(sum=0;i=0,j=0;i=n;i+)sum+=ai;if(i+1)%3=0)/每三个一组求和每三个一组求和 bj=sum;/将和放入新数组中将和放入新数组中 sum=0;/置零,重新累加接下来的三个数置零,重新累加接下来的三个数 j+;第38页,共42页。9.8怎样删除数组元素?21222324252627如何删除如何删除25?删除实质上是通过移动数组元素中的?删除实质上是通过移动数组元素中的值来实
29、现值来实现.for(i=k;in-1;i+0)ai=ai+1;k=5.第39页,共42页。例题例题9.9用选择法对数组中的数进行排序用选择法对数组中的数进行排序选择排序法的思想:选择排序法的思想:从数组从数组0至至n-1中扫描一次选出最小的放到首位,中扫描一次选出最小的放到首位,再从再从1至至n-1找出最小的放到第二位,依次类推找出最小的放到第二位,依次类推 a0 a1 a2 a3 a4 a5即即5 7 4 2 8 6 变量变量p记录最小数位置记录最小数位置m记录最小值记录最小值第一次扫描第一次扫描 1.开始开始p=0,m=5 2.m与与a1比较,比较,54,故故m=4,p=2;4.m与与a3
30、比较,比较,42,故故m=2,p=3;5.m与与a4比较,比较,28,故故m=2,p=3;6.m与与a5比较,比较,26,故故m=2,p=3;此时知最小值为此时知最小值为m=2,位置在,位置在p=3,再将最小值放到首位即,再将最小值放到首位即 a0与与a3交换,此过程可用如下代码实现:交换,此过程可用如下代码实现:第40页,共42页。第一次扫描代码:第一次扫描代码:j=0;/j用来控制扫描次数用来控制扫描次数,也代表了每次扫描的初始位置也代表了每次扫描的初始位置 p=j;/初始化初始化 for(i=j+1;iai)p=i;m=ap;if(apai)p=i;t=aj;aj=ap;ap=t;知知m
31、代表最小元素,代表最小元素,p代表最小元素下标,故代表最小元素下标,故m=ap;则上述程序可以简化如上。则上述程序可以简化如上。结果结果;a0 a1 a2 a3 a4 a5即即2 7 4 5 8 6第二次扫描代码:即从第二次扫描代码:即从a1开始开始,故故j=1 j=1;/j用来控制扫描次数用来控制扫描次数,也代表了每次扫描的初始位置也代表了每次扫描的初始位置 p=j;/初始化初始化 for(i=j+1;iai)p=i;t=aj;aj=ap;ap=t;依次类推三次,四次。依次类推三次,四次。第41页,共42页。思考可以用一个思考可以用一个for循环控制扫描次数故排序程序为:循环控制扫描次数故排序程序为:void arrsort(int*a,int n)int i,j,p,t;for(j=0;jn-1;j+)p=j;for(i=j+1;iai)p=i;if(p!=i)/即最小值的位置不在扫描的初始位置时才有必要交换即最小值的位置不在扫描的初始位置时才有必要交换 t=aj;aj=ap;ap=t;#define NUM 6main()int aNUM=5,7,4,2,8,6;arrout(a,NUM);arrsort(a,NUM);.第42页,共42页。