版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第7章数组7.1一维数组7.2二维数组 7.3数组作为函数的参数7.4字符数组与字符串7.5数组的综合应用程序设计基础1第7章数组本章学习目标从数据存储结构角度理解数组。掌握一维数组的定义、引用、初始化和使用方法。掌握二维数组的定义、引用、初始化和内存映像。理解字符数组,掌握字符串及其处理函数的应用。理解数组在函数中的参数传递过程,掌握数组作为函数参数的方法。程序设计基础2问题:要存储全班30个同学的成绩,需要定义30个独立的变量吗?7.1一维数组—引例intscore1,score2,score3,...,score30;缺陷:变量名多,难以管理。无法使用循环进行批量处理(如输入、排序、输出)。代码冗长、重复,易出错。解决方案:数组。它是一种构造数据类型,可以一次性定义多个相同类型的变量。7.1.1一维数组的定义和使用变量一样,在C语言中使用数组也必须先定义。一维数组的定义形式如下:类型标识符数组名[表达式];例如,floata[5];表示定义了一个名称为a的数组,它由5个“成员”组成,分别是a[0]、a[1]、a[2]、a[3]、a[4],这里的“成员”称为数组的元素。执行floata[5];,系统为数组a分配5个float类型的连续的存储空间
a[0]a[1]a[2]a[3]a[4]例
inta[6];a[0]a[1]a[2]a[3]a[4]a[5]014523a编译时分配连续内存内存字节数=数组元素个数*
sizeof(元素数据类型)数组名表示内存首地址,是地址常量7.1.1一维数组的定义定义数组的语句,如inta[3];,分为三部分,各部分的语法规定如下:(1)第一部分“类型标识符”,用于定义数组每个元素所存储数据的类型。数组存储同类型的数据,都由定义该数组的数据类型确定。(2)第二部分“数组名”必须符合标识符命名规则,且要尽量做到见名知意。(3)第三部分是一对中括号[]内的“表达式”,用于设定所定义数组的元素总数,称为数组长度。[]内的“表达式”的值须为一个正整数,如inta[20],也可以写作inta[10+10],甚至可以使用变量,如intn=20,a[n];。程序设计基础67.1.1一维
数组的定义(4)使用数组多是按元素使用,形如a[0]=4;、a[1]=a[2];,其中a是数组名,中括号[]内的数字称为下标,用于指出使用的是数组的哪个元素。(5)一维数组是在定义数组语句中,数组名后只有一对中括号[],如inta[8]。若有二对中括号[],如inta[5][6],则是二维数组,有几对中括号[]就是几维数组。77.1.1一维
数组的定义(6)定义数组时,表示其长度的“表达式”可以是变量表达式。例如,voidfun_max(intn){inta[2*n]; //定义数组长度为2n,合法
intm=3;intb[2*m]; //也合法。相当于intb[6];}但如果定义数组的语句使用static关键字声明数组是静态(存储)变量,则长度“表达式”中不能出现变量。即如果写作staticinta[2*n];是错误的。提示信息为[Error]storagesizeof'a'isn'tconstant。87.1.1一维数组的定义C语言规定,对数组进行操作时需要按数组的元素进行单独使用。引用的格式如下:数组名[下标]只能引用单个的数组元素,不能一次引用整个数组引用方法:数组名[下标]下标:整型表达式下标取值范围:[0,数组长度-1]数组元素的使用方法与同类型的变量相同scanf("%d",&a[i]);sum=sum+a[i];printf("%d",a[i]);下标不要越界不能使用a[10]7.1.2一维数组的引用只能逐个对数组元素进行操作(字符数组例外)输入方法:inta[10],i;输入第4个数组元素:scanf("%d",&a[3]);输入整个数组元素:for(i=0;i<10;i++)scanf("%d",&a[i]);输出方法:输出第4个数组元素:printf("%d",a[3]);输出整个数组元素:for(i=0;i<10;i++)printf("%d",a[i]);一维数组的常用的输入和输出7.1.2一维数组的引用【例7.1】使用数组存储数值0~9,然后逆序输出。#include<stdio.h>main(){inti,a[10];for(i=0;i<=9;i++)a[i]=i; //循环,依次把0~9赋给a[0]~a[9]。
for(i=9;i>=0;i--)printf("%d",a[i]); //依次输出a[9]~a[0]的值。}117.1.2一维数组的引用7.1.3一维数组的内存映像与地址定义一个数组,系统为数组分配一片连续的存储空间,这片存储空间的大小等于数组的数据类型所占字节数乘以数组的长度。如intb[5];系统将分配5个int类型数据所占的内存空间,一个int型变量占4个字节,即20个字节,这些字节是连续的,其中第0~3这4个字节是元素b[0]的存储空间,第4~7这4个字节是b[1]的存储空间,依此类推,数组b的元素在内存中的映象如图7-2所示。12在定义数组时,为数组元素赋初值(在编译阶段使之得到初值)
inta[5]={1,2,3,4,5};等价于:a[0]=1;a[1]=2;a[2]=3;a[3]=4;a[4]=5;说明:数组不初始化,其元素值为随机数对static数组元素不赋初值,系统会自动赋以0值当全部数组元素赋初值时,可不指定数组长度如inta[5]={6,2,3};
等价于:a[0]=6;a[1]=2;a[2]=3;a[3]=0;a[4]=0;如inta[3]={6,2,3,5,1};(
)staticinta[5];等价于:a[0]=0;a[1]=0;a[2]=0;a[3]=0;a[4]=0;只给部分数组元素赋初值
inta[]={1,2,3,4,5,6};编译系统根据初值个数确定数组长度
7.1.4一维数组的初始化输入10个整数,计算这些数的平均值,再输出所有大于平均值的数。输入:552381122890-178186输出:average=47.10>average:558978186实现本章引例7.1.4一维数组的初始化算法描述:(1)将10个数依次存入a[0],a[1],……a[9],
并计算10个数的和sum=a[0]+a[1]+…+a[9];(2)计算平均值average=sum/10;(3)依次判断a[0],a[1],……a[n-1]是否>平均值,
如果a[i]>average,则输出。for(
i=0;i<10;i++
){scanf(
"%d",&a[i]
);sum=sum+a[i];}for(
i=0;i<10;i++
){if(
a[i]>average
)printf(
"%d",a[i]);}7.1.4一维数组的初始化intmain(void){
inti;doubleaverage,sum;
inta[10];
/*定义数组a,有10个整型元素*/
printf("Enter10integers:");
sum=0;
for(
i=0;i<10;i++
){scanf(
"%d",&a[i]
);sum=sum+a[i];}
average=sum/10;
printf
(
"average=%.2f\n",average
);
printf
(
">average:"
);
for(
i=0;i<10;i++
){if(
a[i]>average
)
printf(
"%d",a[i]
);}
printf
(
"\n"
);
return0;}Enter
10integers:552381122890-178186average=47.10>average:558978186读入10个整数;计算平均值。依次输出大于平均值的数1.一维数组的地址和数组元素的地址数组名是代表数组地址的常指针变量,即C语言中类似符号常量的一种用变量表示常量的方法。一个数组一旦创建成功(即系统为其分配了存储空间),则数组名代表的地址值便不可更改。凡是试图改变数组名值的操作,都将触发语法错误。如定义inta[5]={2,4,6,8,10};,数组名a虽然表面上看像个变量名,但试图为其赋值,如语句a=&x;或a++;都是错误的。7.1.5一维数组与指针的配合使用数组元素可按单个变量求其地址如元素a[2]的地址为&a[2]。也可以用数组名加下标的方式给出,如a+2也是元素a[2]的地址,即&a[2]等价于a+2,若以变量i表示下标,则有&a[i]等价于a+i,a[i]等价于*(a+i)。187.1.5一维数组与指针的配合使用如要输出数组a所有元素的值,可写作地址引用形式:for(i=0;i<5;i++)printf("%4d",*(a+i));此处,printf("%4d",*(a+i));中的*(a+i)是使用地址形式访问数组元素a[i],printf("%4d",a[i]);中的a[i]是按变量名形式访问数组元素,二者是等价的。因为数组名是数组的首地址,而数组的首元素的下标为0,故有a、a+0、&a[0]三者等价,都是元素a[0]的地址,也就是数组首元素的地址、数组地址。197.1.5一维数组与指针的配合使用2.“指向”一维数组的指针变量数组名虽貌似指针变量,但其值不可更改。有时需要以指针变量的形式引用数组元素,则可以定义一个和数组同类型的指针变量,在将数组名赋给该指针变量之后,就可以按指针变量的方式访问数组了。例如,inti,a[10],*p;p=a;//将数组的地址赋给指针p当p“指向”数组时,p=p+1是让指针p指向下一个元素。207.1.5一维数组与指针的配合使用如果指针p“指向”数组的首地址,那么*(p+i)、a[i]、p[i]具有相同的意义,都表示第i个元素。输出数组a的各元素的值也可以写作依据指针变量访问形式。for(i=0;i<5;i++)printf("%4d",*(p++));循环体语句或者写作:printf("%4d",*(p+i));,但写作*(p++)时,每循环一次,指针变量p的值增加1,即指向下一个元素。循环结束,p指向数组的最后一个元素的地址,在循环过程中p的值由“指向”元素a[0]到“指向”元素a[4]。而写作*(p+i),指针p的值始终未发生改变。C++面向对象程序设计217.1.5一维数组与指针的配合使用【例7.2】使用指针变量操作数组。#include<stdio.h>main(){inta[5],k,*p; //定义数组a与同类型的指针变量pp=a; //使p指向a的第一个元素for(k=0;k<5;k++)
scanf("%d",p++);//输入5个数,依次存入元素a[0]~a[4]p=a;//令p重新指向数组a的第一个元素for(k=0;k<5;k++)printf("%6d",*(p++));//依次输出数组元素}227.1.5一维数组与指针的配合使用【例7.3】使用不同的方式输出数组各元素的值。#include<stdio.h>main(){inta[5]={1,3,5,7,9};inti,*p;for(i=0;i<5;i++)printf("%6d",a[i]); //以数组元素下标方式printf("\n");for(i=0;i<5;i++)printf("%6d",*(a+i)); //以数组元素的地址方式printf("\n");for(p=a;p<a+5;p++)printf("%6d",*p); //以指针变量方式printf("\n");
p=a;for(i=0;i<5;i++)printf("%6d",p[i]); //把指针变量当作数组名,元素下标方式}p=a;printf("\n");这两行代码颠倒一下位置程序设计基础237.1.5一维数组与指针的配合使用【例7.4】输入一组整数,输出其中的最大值及其所在数组元素的下标。程序设计基础247.1.6使用一维数组的程序举例步骤:1.输入:for循环输入n个整数2.处理:(a)先令max=min=x[0](b)依次用x[i]和max,min比较(循环)若max<x[i],令max=x[i]
若min>x[i],令min=x[i]3.输出:max和min#include<stdio.h>#defineSIZE10main(){intx[SIZE],i,max,min;printf("Enter10integers:\n");
for(i=0;i<SIZE;i++){printf("%d:",i+1); scanf("%d",&x[i]);}
max=min=x[0];for(i=1;i<SIZE;i++){if(max<x[i])max=x[i];if(min>x[i])min=x[i];}
printf("Maximumvalueis%d\n",max);printf("Minimumvalueis%d\n",min);}如果记录最大值及最小值的下标,并输出,该如何处理呢?7.1.6使用一维数组的程序举例【例7.5】对存储在数组中的10个学生的成绩进行递增排序,并输出排序结果。冒泡排序的基本思路:①将第1个数与第2个数比较。若第1个数大于第2个数,则互换;再将第2个数与第3个数比较,…,第n-1个与第n个数比较,共比较n-1次;将n个数中的最大数“沉”到最底下(第n个位置),它将不参与以后的排序操作;②第2轮排序时,将第1个数与第2个数进行比较,…,直到完成第n-2个数与第n-1个数的比较,将n-1个数中的最大数沉到最底下(第n-1个位置);③如此重复,直到第n-1轮排序。将第1个数与第2个数进行比较,若符合所要求的顺序,则结束冒泡排序;若不符合所要求的顺序,则交换两个数的位置,然后结束冒泡排序。程序设计基础25
#include<stdio.h>#defineN10
voidmain(){inti,j,a[N],t;printf("输入数据:");for(i=0;i<N;i++)scanf("%d",&a[i]);
for(i=0;i<N-1;i++)for(j=0;j<N-i-1;j++)
if(a[j]>a[j+1])
//若为逆序,则相互交换
t=a[j],a[j]=a[j+1],a[j+1]=t;
//逗号表达式,实现数据的交换
printf("输出结果:");for(i=0;i<N;i++)printf("%-4d",a[i]);}7.1.6使用一维数组的程序举例【例7.5】对存储在数组中的10个学生的成绩进行递增排序,并输出排序结果。冒泡排序的基本思路:①将第1个数与第2个数比较。若第1个数大于第2个数,则互换;再将第2个数与第3个数比较,…,第n-1个与第n个数比较,共比较n-1次;将n个数中的最大数“沉”到最底下(第n个位置),它将不参与以后的排序操作;②第2轮排序时,将第1个数与第2个数进行比较,…,直到完成第n-2个数与第n-1个数的比较,将n-1个数中的最大数沉到最底下(第n-1个位置);③如此重复,直到第n-1轮排序。将第1个数与第2个数进行比较,若符合所要求的顺序,则结束冒泡排序;若不符合所要求的顺序,则交换两个数的位置,然后结束冒泡排序。程序设计基础277.1.6使用一维数组的程序举例【例7.6】从键盘输入一个多位的正整数,判断其是否为回文数。所谓回文数,是指一个整数,正序和逆序读是一样的。如整数12321、1357531。冒泡排序的基本思路:①将第1个数与第2个数比较。若第1个数大于第2个数,则互换;再将第2个数与第3个数比较,…,第n-1个与第n个数比较,共比较n-1次;将n个数中的最大数“沉”到最底下(第n个位置),它将不参与以后的排序操作;②第2轮排序时,将第1个数与第2个数进行比较,…,直到完成第n-2个数与第n-1个数的比较,将n-1个数中的最大数沉到最底下(第n-1个位置);③如此重复,直到第n-1轮排序。将第1个数与第2个数进行比较,若符合所要求的顺序,则结束冒泡排序;若不符合所要求的顺序,则交换两个数的位置,然后结束冒泡排序。程序设计基础28程序设计基础29#include<stdio.h>main(){inti,k;
long
longn,m; //用于存储长整型数据,因输入的整数要求多位intdigit[10]; //用于存储把长整数分离成的各位上的数字printf("请输入一个不超过10位的整数:"); //操作提示scanf("%lld",&n); //从键盘输入多位的整数存入变量nm=n; //把n的值赋给m,对m分离数字,把n的原值保护起来k=0; //作为元素下标while(m!=0) //循环将m存储的数分离为一位一位的数字,当m等于0时分离完毕{digit[k]=m%10; //m除以10的余数是最低位数字,把它存入数组元素k++; //下标k增1m=m/10; //m除以10的商再存入m,相当于抹去了最低位数字}k--; //当m中的数分离完成,k的值多增加了一次,故要减回。for(i=0;i<k;i++,k--) //判断是否为回文数if(digit[i]!=digit[k])break; //不相等,则不是回文数,提前退出循环if(i<k)printf("%lld不是回文数.",n);elseprintf("%lld是回文数.",n);}第7章数组7.1一维数组7.2二维数组 7.3数组作为函数的参数7.4字符数组与字符串7.5数组的综合应用程序设计基础30二维数组是具有两个下标的数组。二维数组的定义形式为:类型标识符
数组名[长度表达式1][长度表达式2];例如,inta[3][4];,该语句定义了一个名为a的二维数组。根据该语句可知:(1)数组a中每个元素都是int型。(2)数组a中共有3x4个元素。(3)数组a的逻辑结构是一个具有如下形式的3行4列的矩阵(或表格)。7.2.1二维数组的定义
7.2.1二维数组的定义
第0列第1列第2列第3列第0行a[0][0]a[0][1]a[0][2]a[0][3]第1行a[1][0]a[1][1]a[1][2]a[1][3]第2行a[2][0]a[2][1]a[2][2]a[2][3]二维数组适合表示具有行和列的数据表格(矩阵)。二维数组的第一个下标称为行下标,用于标识数组元素所在行的行号,第二个下标称为列下标,用于标识数组元素所在列的列号。行号与列号均从0开始。如元素a[0][2]位于数组a的第0行第2列的位置。C语言允许把二维数组按“一维”数组使用,只不过这个一维数组的每个元素,也是一个一维数组。先定义,后使用数组元素的引用
数组名[行下标][列下标]行下标的取值范围:[0,行数-1]列下标的取值范围:[0,列数-1]
inta[3][2];3行2列,6个元素a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]下标不要越界7.2.2二维数组的使用方法整型表达式inta[3][2];3行2列,6个元素表示1个3行2列的矩阵
a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]存放顺序:按行存放,线性存储
a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]7.2.3二维数组所分配的存储空间4.二维数组元素的初始化分行初始化:
例inta[2][3]={{1,2,3},{4,5,6}};a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]123456全部初始化按元素排列顺序初始化
例inta[2][3]={{1,2},{4}};a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]120400部分初始化
例inta[][3]={{1},{4,5}};a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]100450第一维长度省略初始化
例inta[2][3]={1,2,3,4,5,6};a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]123456全部初始化
例inta[2][3]={1,2,4};a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]124000部分初始化
例inta[][3]={1,2,3,4,5};a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]123450第一维长度省略初始化7.2.4二维数组的初始化数组的输入和输出只能逐个对数组元素进行操作(字符数组例外)inta[2][3],i,j;输入方法:输入第1行第2列元素:scanf("%d",&a[0][1]);输入整个数组元素:for(i=0;i<2;i++)for(j=0;j<3;j++)scanf("%d",&a[i][j]);输出方法:输出第1行第2列元素:printf("%d",a[0][1]);输出整个数组元素:for(i=0;i<2;i++){for(j=0;j<3;j++)printf("%d",a[i][j]);printf("\n");}7.2.4二维数组的初始化程序举例1.数组转置2.求极值问题3.求和、求均值问题1.数组转置例将二维数组行列元素互换,存到另一个数组中a=123456b=142536#include<stdio.h>main(){inta[2][3]={{1,2,3},{4,5,6}};intb[3][2],i,j;printf("arraya:\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("arrayb:\n");
for(i=0;i<=2;i++){for(j=0;j<=1;j++) printf("%5d",b[i][j]);printf("\n");}}【例】试编程找出二维数组a[4][5]中最大和最小的元素,并指出它们所在的行号和列号。1.求极值问题分析:(1)如何存储4*5的矩阵?(2)如何找出最大值及最小值?(3)如何确定最大值及最小值的位置?【例】试编程找出二维数组a[4][5]中最大和最小的元素,并指出它们所在的行号和列号。#include<stdio.h>main(){inta[4][5],i,j,max,max_row,max_col;intmin,min_row,min_col;printf("输入二维数组如下:\n");
for(i=0;i<4;i++)for(j=0;j<5;j++)scanf("%d",&a[i][j]);max=a[0][0];max_row=0;max_col=0;
min=a[0][0];min_row=0;min_col=0;
for(i=0;i<4;i++)for(j=0;j<5;j++){if(max<a[i][j])max=a[i][j],max_row=i,max_col=j;if(min>a[i][j]){min=a[i][j],min_row=i,min_col=j;}
}printf("输出结果如下:\n");printf("max=%d,row=%d,column=%d\n",max,max_row,max_col);printf("min=%d,row=%d,column=%d\n",min,min_row,min_col);
}输入数据max=a[0][0],row1=0,column1=0min=a[0][0],row2=0,column2=0输出结果max<a[i][j]min>a[i][j]max=a[i][j],row1=i,column1=jmin=a[i][j],row2=i,column2=j2.求极值例:读入下表中值到数组,分别求各行、各列及表中所有数之和939492576058705762606383939492576058705762606383#include<stdio.h>main(){intx[5][4],i,j;
for(i=0;i<4;i++)for(j=0;j<3;j++)scanf("%d",&x[i][j]);
for(i=0;i<3;i++)x[4][i]=0;for(j=0;j<5;j++)x[j][3]=0;3.求和、求均值问题#include<stdio.h>main(){intx[5][4],i,j;…for(i=0;i<4;i++)for(j=0;j<3;j++){x[i][3]+=x[i][j];x[4][j]+=x[i][j];x[4][3]+=x[i][j];
}for(i=0;i<5;i++){for(j=0;j<4;j++)printf("%5d\t",x[i][j]);printf("\n");}}例:读入下表中值到数组,分别求各行、各列及表中所有数之和3.求和、求均值问题9394925760587057626063839394922795760581757057621896063832122862732958557.2.5二维数组和指针的配合使用1.二维数组的地址与二维数组元素的地址二维数组实质上就是一个一维数组,只不过其数组元素又都是一个一维数组。若有定义inta[2][3];,则可认为数组a由a[0]、a[1]两个元素组成,而a[0]、a[1]又分别是由3个整型元素组成的一维数组。可用a[0][0]、a[0][1]等引用数组a[0]中的每个元素,a[0]作为数组的名字,是数组a[0]的地址。【例7.9】使用指针变量,输出二维数组的各元素的值。分析:对于二维数组a[2][3],a[0]是第0行首地址,a[0]+2是该行第2列元素的地址,那么使用*运算符作用于地址,可得该地址存储的数值,即*(a[0]+2)就是元素a[0][2]。依次类推,a[1]是第1行首地址,a[2]是第2行首地址,用循环即可遍历所有元素。7.2.5二维数组和指针的配合使用#include<stdio.h>main(){inta[2][3]={0,1,2,3,4,5}; //定义二维数组并初始化
inti,j,*p;//定义指针变量pfor(i=0;i<2;i++) //方式1{for(j=0;j<3;j++)printf("%5d",*(a[i]+j)); //a[i]是i行首地址,a[i]+j是i行j列元素的地址
putchar('\n'); //输出换行符
}for(i=0;i<2;i++) //方式2{for(j=0;j<3;j++)printf("%5d",*(*(a+i)+j)); //*(a+i)+j)是i行j列元素的地址
putchar('\n'); //输出换行符
}p=a[0]; //把二维数组a当作一维数组,p指向第一个元素,注意不是p=a;
for(i=0;i<2;i++) //方式3{for(j=0;j<3;j++)printf("%5d",*(p++)); //输出p所指示的元素,一次循环输出一行
putchar('\n'); //输出换行符
}}程序设计基础457.2.5二维数组和指针的配合使用【例7.10】用指向数组元素的指针输出二维数组所有元素所存的值,并将数组最大元素及其所在元素的行列下标值输出467.2.5二维数组和指针的配合使用#include<stdio.h>main(){inti,j,m,n,max;inta[2][3]={1,2,3,4,5,6};int*p; //定义指针变量pp=a[0]; //指针p指向数组a的第0行首地址
max=*p; //先把p所指向元素存储的值作为最大值
m=n=0;for(i=0;i<2;i++) //先输出数组a的所有元素存储的值
{printf("\n"); //先换行
for(j=0;j<3;j++) //输出一行元素的值
{printf("%-5d",*p); //输出p所指向元素的值
if(max<*p) //如p所指向元素的值是目前位置最大的,将其赋给max{max=*p;m=i;n=j; //记住当前最大值所指元素的两个下标值
}p++; //指针p指向本行的下一个元素
}}printf("\nmaxis:a[%2d][%2d]=%-5d",m,n,max);}477.2.5二维数组和指针的配合使用【例7.11】用二维数组的名字输出二维数组所有元素所存的值,并将数组最大元素及其所在元素的行列下标值输出。#include<stdio.h>main(){inti,j,m,n,max;inta[2][3]={1,2,3,4,5,6};m=n=0;max=**a; //第一个元素赋给max,**a等价于*(*(a+0)+0)for(i=0;i<2;i++){printf("\n"); //先换行
for(j=0;j<3;j++){printf("%-5d",*(*(a+i)+j));if(max<*(*(a+i)+j)){max=*(*(a+i)+j);m=i;n=j;}}}printf("\nmaxis:a[%2d][%2d]=%-5d",m,n,max);}7.2.5二维数组和指针的配合使用第7章数组7.1一维数组7.2二维数组 7.3数组作为函数的参数7.4字符数组与字符串7.5数组的综合应用程序设计基础49在定义函数的函数头代码中,()里的参数称为形参,而在调用函数的语句中,()里给出的是实参。形参在乎数据类型和名称,函数体内使用形参按假想的数据编写表达式,实参在乎数据类型和值,调用函数先把实参值传递给形参变量。数组也是变量,只不过它是一个复合型变量。如果自定义函数要处理数组中的数据,则需要把数组分别用作形参和实参。本节介绍数组作为函数参数的用途和有关规定。7.3数组作为函数的参数一维数组作为函数参数程序设计基础51本质:传递的是数组的地址,属于“地址传递”。形参的三种写法(完全等价,都是指针):voidfun(intarr[],intsize)voidfun(intarr[10],intsize)voidfun(int*arr,intsize)特性:在被调函数中修改形参数组元素的值,会直接影响实参数组。voidprintArray(intarr[],intn){for(inti=0;i<n;i++)printf("%d",arr[i]);}1.一维数组用作形参voidfun1(inta[],intm)
{inti;for(i=0;i<m;i++)printf("%d\n",a[i]);}7.3.1数组用作函数形参voidfun2(int*a,intm){inti;for(i=0;i<m;i++)
printf("%d\n",a[i]);}:当把数组名作为函数形参,如inta[],系统也是把a看作是一个指针变量,即用作函数形参的两种方式inta[]与int*a是完全等价的,所声明的标识符a都是一个指针变量的名字,而不是一个真正数组的名字。【例7.13】一维数组作为函数参数的使用例子。验证:(1)形参数组不是数组,而是指针变量。(2)函数体内对形参数组值的改变,就是改变实参数组本身。7.3.1数组用作函数形参#include<stdio.h>voidss(inta[]){printf("系统为形参a分配的存储空间字节数=%d\n",sizeof(a)); //验证a是一个指针变量a[0]++; //把形参"数组"的元素值改变,验证此改变是否影响实参数组}main(){intb[5]={1,1,1,1,1}; //定义数组并为每个元素赋初值1printf("系统为实参b分配的存储空间字节数=%d\n",sizeof(b));printf("b[0]=%d\n",b[0]); //显示数组元素b[0]的值ss(b); //调用函数ss(),把数组b作为实参,把数组地址传递给ss()的形参printf("b[0]=%d\n",b[0]);//调用函数ss()之后再显示数组元素b[0]的值,验证ss()内对形参的改变,影响了实参数组}【例7.14】冒泡法排序。冒泡法的基本思想是:相邻两数比较,若前面的数大,则两数进行交换位置,直至最后一个元素被处理,最大的元素就被排在最后一个元素位置。这样,若有n个元素,共进行n-1轮,每轮让剩余元素中最大的元素排到下面,从而完成排序。实际上,n-1轮是最多的排序轮数,而只要在某一轮排序中没有进行元素交换,则说明已经完成排序,可以提前退出外循环,结束排序。这里为了说明数组如何用作函数的参数,特意把排序的实现写成一个函数sort(),而把待排序的数组作为它的参数。7.3.1数组用作函数形参#include<stdio.h>#defineN80voidsort(int*b,intk); //排序函数,对形参指针变量b所指向的数组进行冒泡排序voidprint(int*b,intk); //输出形参指针变量b所指向的数组各元素的值main(){inta[N]; //定义数组a,长度为符号常量N,即80inti,m; //变量i用于控制循环
printf("\n请输入数组的实际长度m(<80):");scanf("%d",&m);for(i=0;i<m;i++)scanf("%d",&a[i]);sort(a,m);print(a,m);}voidsort(int*b,intk) //对形参指针b所"指向"的数组进行冒泡排序{inti,j,t,flag;for(j=0;j<k-1;j++) //外循环,每循环一次,冒出一个最大者
{flag=0; //设变量flag为标记,其值作为是否提前结束排序的标记
for(i=0;i<k-j-1;i++) //内循环,把b[0]~b[k-j-1]之间最大者交换到b[k-j-1]if(b[i]>b[i+1]){t=b[i];b[i]=b[i+1];b[i+1]=t;flag=1;}if(flag==0)break;}}voidprint(intb[],intk) //以每行4个输出数组各元素的值{inti;for(i=0;i<k;i++){printf("%-6d",b[i]); //输出元素b[i]的值
if((i+1)%4==0)printf("\n"); //每输出够4个,换行
}}程序设计基础55程序说明:sort()实现排序,其形参数组b没有说明长度,而是通过另一形参k决定处理元素的个数,但k的值不能超过实参数组的大小。由于数组名作为函数参数时,传递的是数组的起始地址,形参接收实参数组的起始地址值,形参与实参共用相同的存储区域,sort()中将数组b排好序,也就是将a排好了序。这也是数组作为参数与其他基本类型变量作为参数所不同的。采用函数实现的另外一个好处就是在函数处理排序时,只需要在调用函数sort()时采用不同的实参,就可以完成对不同数组进行排序。1.数组元素作为函数实参数组元素就是一个变量,把它用作实参,传递给形参变量的是数组元素所存储的值。这和普通变量作为实参,在用法与含义方面并无不同。使用数组元素向形参传递的是数组元素的值,即是“值传递”方式,数据传递方向是“从实参传到形参,单向传递”,形参变量和作为实参的数组元素是两个不同的变量,二者只是在调用时做了一下“值传递”,因此,在函数中对形参变量值的改变,丝毫不影响实参变量。7.3.2数组用作函数实参【例7.15】输入10个实数存放在数组中,利用函数将数组元素的值扩大2倍并输出。分析:首先利用for循环处理10个实数输入并存放在数组a中,调用自定义函数doubnum(),然后输出调用函数后数组每个元素的值。7.3.2数组用作函数实参#include<stdio.h>voiddoubnum(inta){a=2*a;}main(){ inti; inta[10]; printf("输入10个整数:"); for(i=0;i<10;i++) scanf("%d",&a[i]); for(i=0;i<10;i++){doubnum(a[i]);
printf("a[%d]=%d\n",i,a[i]);}}2.一维数组名作函数实参真正地把数组作为参数,是指在调用函数时,把数组名用作实参,这样可以把数组的全部元素都“传递”给形参,进而交由函数处理。数组名作函数实参时,向形参(数组名形式或指针变量形式)传递的是数组的地址,其数组所占用那块存储空间的起始地址。因此,把数组名作为实参,实参与形参结合时进行的是“地址”传递。即把实参数组的地址传递给形参(数组)指针变量,这样形参“数组”和实参数组是同一个数组,函数中对形参数组的改变,就是直接改变实参数组。7.3.2数组用作函数实参【例7.16】编写函数用于将一个数组里存储的多名学生一门课程的成绩从高到低进行排序。在main()函数里定义数组,录入成绩,调用函数将成绩排序。7.3.2数组用作函数实参#include<stdio.h>voidsort(floata[],intn) {inti,j,flag;
floatt;for(i=0;i<n-1;i++) {flag=0;for(j=0;j<n-i-1;j++)if(a[j]<a[j+1])
{t=a[j];a[j]=a[j+1];a[j+1]=t;flag=1;}if(flag==0)break;}}main(){
floatscore[5],av;inti;printf("输入5个成绩:\n");for(i=0;i<5;i++)scanf("%f",&score[i]);sort(score,5); //调用函数sort(),数组名作实参。for(i=0;i<5;i++)printf("%.1f",score[i]);}3.二维数组名作为函数实参将二维数组名作为实参时,其对应的形参必须是一个行指针变量,而且形参的第二维必须指定大小。但在对函数进行声明时可以只指定维数,不指定各维大小。7.3.2数组用作函数实参例如,如果主函数中有以下定义和函数调用语句:#include<stdio.h>#defineM2#defineN3main(){doublea[M][N];...fun(a);...}则fun()函数的首部可以是以下三种形式之一。fun(double(*a)[N])fun(doublea[][N])fun(doublea[M][N])【例7.17】打印7行的杨辉三角。杨辉三角形
1111211331146411510105116152015617.3.2数组用作函数实参程序分析:可以将杨辉三角形的值放在一个方形矩阵的下半三角中,如果需打印7行杨辉三角形,应该定义一个大于7×7的方形矩阵,只是矩阵的上半部和其余部分并不使用。杨辉三角形具有如下特点:(1)第一列和对角线上的元素都为1。(2)除第一列和对角线上的元素之外,其他元素的值均为前一行上的同列元素和前一列元素之和。函数setdata()按以上规律给数组元素置数;函数outdata输出杨辉三角形。#include<stdio.h>#defineN10voidsetdata(int(*s)[N],intn){inti,j;for(i=0;i<n;i++) {s[i][i]=1;//将对角线位置的元素赋值为1s[i][0]=1;//第0列的元素都赋值为1}for(i=2;i<n;i++) //给杨辉三角形其他元素置数
for(j=1;j<i;j++)s[i][j]=s[i-1][j-1]+s[i-1][j];}voidoutdata(ints[][N],intn){inti,j;puts("杨辉三角形");for(i=0;i<n;i++) //注意:只输出矩阵的下半三角
{for(j=0;j<=i;j++)printf("%-6d",s[i][j]);printf("\n");
}}main(){inty[N][N],n=7;setdata(y,n); //按规律给数组元素置数
outdata(y,n); //输出杨辉三角形}7.3.2数组用作函数实参4.指针数组作为函数实参将指针数组名作为实参时,其对应的形参必须为一个指向指针的指针。例如,如果主函数中有以下定义和函数调用语句。#include<stdio.h>#define M5#define N3main(){doubles[M][N],*p[M];...for(i=0;i=<M;i++)p[i]=s[i];fun(p);...}则fun函数的首部可以使以下三种形式之一。fun(double *a[M])fun(double *a[])fun(double **a )7.3.3函数的指针形参和函数体中数组的区别若有以下程序,程序中定义了fun函数,形参a指向主函数中的w数组,函数体内定义了一个b数组,函数把b数组的起始地址作为函数值返回,企图使主函数中的指针p指向函数体内b数组的开头。#include<stdio.h>#defineN10int*fun(inta[N],intn){intb[N];︙returnb;}main(){intw[N],*p;︙p=fun(w,N);︙}第7章数组7.1一维数组7.2二维数组 7.3数组作为函数的参数7.4字符数组与字符串7.5数组的综合应用程序设计基础64C语言初学者编程经常使用的数据有两种类型,一种是用于加减乘除等算术运算的“数”,如3、3.14等,其类型如int、float、double,这些类型的数也可以存储在变量里,然后借助变量去使用。另一种就是字符串,实质上是一串字符,如"llovec",即用双引号括起来的字符序列。“数”关注的是值的大小,“字符串”关注的是它串起来的字符及字符之间的位置关系。C语言没有提供用定义字符串变量的数据类型。C语言规定字符串需用char类型的字符数组来存储,处理字符串可以通过处理存储它的字符数组来实现。7.4字符数组与字符串1.字符串与字符数组所谓字符数组是指用数据类型关键字char定义的数组,如chars[20];,用于存储一串char型数据。字符数组的一个元素所占存储空间是1个字节,只能存放一个字符。字符串中字符排列是线性的,字符之间有位置前后关系,存储字符串不仅需要存储它包含的字符,还要“存储”各个字符之间的位置关系。一维的char类型数组刚好可以用于存储字符串。7.4.1使用一维字符数组存储字符串C语言规定把字符'\0'作为字符串的结尾标记。'\0'是ASCII值为0的特殊字符。'\0'仅仅是被作为字符串的结尾“标记”,它不是字符串的组成字符,字符串的长度是指字符串中不含'\0'的字符个数。但使用字符数组存储字符串时,系统会自动把字符串的结束标记'\0'也用一个元素存储起来。因此一个长为n的字符串,需要一个长不小于n+1的字符数组才能存储它。如字符串"abc"的长度是3,存储它的字符数组的长度至少为4。7.4.1使用一维字符数组存储字符串2.字符数组初始化字符数组可谓专为存储字符串而存在,字符数组初始化即在定义字符数组的语句中给数组赋初值,例如,charstr[10]="hello";。这样系统在为字符数组分配存储空间之后,立即将指定的字符串存储到数组所分配的存储空间。如果只定义字符数组但不对其初始化,则字符数组各元素所存储值并不确定。例如,7.4.1使用一维字符数组存储字符串#include<stdio.h>main(){chars[5];//定义字符数组s,其各元素的初值不确定,不一定都是0inti;for(i=0;i<5;i++)printf("%4d",s[i]);//按整数形式输出数组s中各元素的值}字符串的输入输出整个字符串I/O:%s例用%smain(){charstr[5];scanf("%s",str);printf("%s",str);}用字符数组名,不要加&输入串长度<数组长度遇空格或回车结束自动加‘\0’用字符数组名,遇‘\0’结束例main(){chara[5]={'H','e','l','l','o'};printf("%s",a);}例main(){chara[]="Hello";printf("%s",a);}结果:Hello
hello02314结果:Hello用"%s"输出时,遇'\0'结束main(){chara[]={'h','e','l','\0','l','o','\0'};printf("%s",a);}例输出:hel
hel\0lo\0数组中有多个‘\0’时,遇第一个结束例字符串输入举例
How\0
are\0
you?\0
#include<stdio.h>main(){chara[15],b[5],c[5];
scanf("%s%s%s",a,b,c);
printf("a=%s\nb=%s\nc=%s\n",a,b,c);}运行情况:输入:Howareyou?输出:a=Howb=arec=you?scanf中%s输入时,遇空格或回车结束【例7.18】判断一个字符串是不是回文字符串。所谓回文字符串就是正读和反读都一样的字符串。例如,"agpga"是一个回文字符串。分析:回文字符串的特征是,如果字符数组有n个元素,那么a[0]和a[n-1]是相同的;a[1]和a[n-2]是相同的;……依此类推。可以用一个循环比较n/2次就可以得到结果。如果n为偶数,比较进行n/2次。如果n为奇数,a[n/2]这个元素正好是n个元素的中间元素,不用进行比较,也进行n/2次。7.4.1使用一维字符数组存储字符串【例7.18】判断一个字符串是不是回文字符串。所谓回文字符串就是正读和反读都一样的字符串。例如,"agpga"是一个回文字符串。分析:回文字符串的特征是,如果字符数组有n个元素,那么a[0]和a[n-1]是相同的;a[1]和a[n-2]是相同的;……依此类推。可以用一个循环比较n/2次就可以得到结果。如果n为偶数,比较进行n/2次。如果n为奇数,a[n/2]这个元素正好是n个元素的中间元素,不用进行比较,也进行n/2次。7.4.1使用一维字符数组存储字符串#include<stdio.h>#include<string.h>main(){chars[100];inti,nLen,nResult=1;
printf("\n输入字符串:");
gets(s); nLen=strlen(s); 7.4.1使用一维字符数组存储字符串for(i=0;i<nLen/2;i++) if(s[i]!=s[nLen-1-i])
{nResult=0; break;
} if(nResult==1)
printf("这个字符串是回文字符串");elseprintf("这个字符串不是回文字符串");}%s用在printf()中,主要是通过把%s替换为一个字符串,从而实现拼接成一个较长的字符串,例如,printf(“输出的字符串是%s”,“ABCD”);,‘\0’结束包含在头文件“stdio.h”中使用printf()函数输出字符数组所存储的字符串分为两种:第一种方法,逐个字符输出,即用格式符“%c”;第二种方法,将整个字符串一次输出,即用格式符“%s”。’结束字符串的输入、输出可以使用printf()和scanf()这两个函数。约定数据为字符串的格式符是%s,如printf("%s","ABCD");,表示把%s用字符串常量"ABCD"替换后作为一个字符串输出。例inti;charstr[20]="hello";printf("%s",str); //输出字符串hello与下面不同:for(i=0;i<5;i++)printf("%c",str[i]);
7.4.2输入、输出字符串的函数包含在头文件“stdio.h”中字符串输出函数puts格式:puts(字符数组)功能:向显示器输出字符串(输出完,换行)说明:字符数组必须以‘\0’结束字符串输入函数gets格式:gets(字符数组)功能:从键盘输入一以回车结束的字符串放入字符数组中,并自动加‘\0’说明:输入串长度应小于字符数组长度例#include<stdio.h>mai
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- THR-β-modulator-3-生命科学试剂-MCE
- 2025-2030年足球运动用品和器械行业市场营销创新战略制定与实施分析研究报告
- 2025-2030年港口智能客户服务系统企业制定与实施新质生产力战略分析研究报告
- 煤气化行业市场营销创新战略制定与实施分析报告
- 养老护理员急救培训基地管理
- 服装设计师服装设计工作室团队绩效衡量表
- 八纲辨证护理操作规范
- 中医护理管理核心技能培训
- 产后护理健康要点
- 中专护理医学护理职业挑战课件
- 广东能源集团笔试题库
- 人教版八年级语文上册《新闻写作》示范公开教学课件
- DL∕T 1848-2018 220kV和110kV变压器中性点过电压保护技术规范
- 市红十字医院档案管理三合一制度样本
- 课堂观察走向专业的听评课崔允漷课件
- 诸暨市城北片控制性详细规划
- 利乐无菌包装原理(NXPowerLite)
- 过程控制系统与仪表
- 电路检查记录表
- 医院临床教学管理制度汇编
- 北师大版六年级下册数学课件 利润问题 整理课件
评论
0/150
提交评论