数组作函数参数函数嵌套与递归调用变量作用域.docx
《数组作函数参数函数嵌套与递归调用变量作用域.docx》由会员分享,可在线阅读,更多相关《数组作函数参数函数嵌套与递归调用变量作用域.docx(18页珍藏版)》请在冰豆网上搜索。
![数组作函数参数函数嵌套与递归调用变量作用域.docx](https://file1.bdocx.com/fileroot1/2023-1/10/7bd2116d-c82b-4faf-b28a-ab24f501b7c5/7bd2116d-c82b-4faf-b28a-ab24f501b7c51.gif)
数组作函数参数函数嵌套与递归调用变量作用域
《C语言程序设计》教案
19-数组作函数参数、函数嵌套调用、变量作用域
教师姓名
韩晓翠
授课班级
授课形式
边讲
边练
授课日期
年月日第周
授课时数
授课章节
第7章用函数实现模块化程序设计
7.5函数嵌套调用
7.6函数递归调用
7.7数组名作函数参数
7.8-7.11变量作用域
教学目的
熟练掌握数组元素作函数参数
熟练掌握数组名作函数参数
掌握函数的嵌套调用
熟悉变量的作用域
教学重点
数组元素作函数参数
数组名作函数参数
教学难点
数组名作函数参数
变量的作用域
教学内容
授课要点
数组元素作函数参数
数组名作函数参数
函数的嵌套调用
变量的存储类别和作用域
一、数组元素作函数参数
数组元素作函数参数和普通变量作函数参数效果和用法一样
问题1:
调用函数输出数组元素的值。
问题1解决:
#include
voidmyfun(intx,inty,intz);
main()
{inta[3]={1,2,3};
myfun(a[0],a[1],a[2]);
}
voidmyfun(intx,inty,intz)
{printf("%d,%d,%d\n",x,y,z);}
运行结果:
1,2,3
注:
数组元素作函数参数实现的是“值传递”。
如:
#include
voidswap1(intx,inty)
{intz;
z=x;x=y;y=z;
}
main()
{inta[2]={1,2};
swap1(a[0],a[1]);
printf("a[0]=%d\na[1]=%d\n",a[0],a[1]);
}
二、数组名作函数参数
数组名作函数参数——地址传递
C语言规定,不带任何下标的数组名代表数组的首地址,即第一个元素的地址
例如,有定义语句intnum[10];那么,数组名num和&num[0]的意义是相同的。
采用数组名作为函数参数就是将数组的首地址作为函数参数传递给被调用的函数。
例如,以下程序段是把数组num的地址传给函数sort():
main()
{intnum[10];
/*……*/
sort(num);
/*……*/
}
接收数组num的函数既可以定义为:
voidsort(intarr[10])
{
/*……*/
}
也可以定义为:
voidsort(intarr[])
{
/*……*/
}
即使定义为:
voidsort(intarr[20])
{
/*……*/
}
程序编译时也不会报错。
因为C编译程序产生的代码是令函数sort()接收数组num的首地址,并不生成具有20个元素的数组arr,也不进行下标边界检查。
为了避免发生错误,向函数传递数组时,最好同时再用一个参数传递数组的长度。
例如,对于上面的例子可以写程序:
main()
{intnum[10];
/*……*/
sort(num,10);
/*……*/
}
voidsort(intarr[],intn)
{
/*……*/
}
问题2:
实现两个整型变量的值的互换。
(假设两个整型变量是一个长度为2的整型数组的元素)
问题2解决---自定义函数
#include
voidswap2(intx[2])//形参用数组定义,等价于intx[]
{
intz;
z=x[0];
x[0]=x[1];
x[1]=z;
}
main()
{inta[2]={1,2};
swap2(a,2);
printf("a[0]=%d\na[1]=%d\n",a[0],a[1]);
}
问题3:
定义一个函数,求全班学生的某门课程总分,并将总分返回到主函数中输出。
问题3解决---自定义函数求总分
#include
floatsum(floatstu[],intn);
voidmain()
{floatscore[10];inti;
floattotal;
printf("Input10scores:
\n");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
total=sum(score,10);//实参用数组名
printf("sumis:
%f\n",total);
}
floatsum(floatstu[],intn)//形参用数组定义
{inti;
floattotal=0;
for(i=0;itotal+=stu[i];
returntotal;
}
数组名作函数参数总结
•数组名作函数参数——地址传递
•在主调函数与被调函数分别定义数组,且类型应一致,实参用数组名,形参用数组定义
•形参、实参数组名是地址变量
模仿练习
1、输入10个整数保存到数组中,定义函数求最大元素和该数是第几个数。
2、在主函数输入8个整数保存到数组中,自定义函数对数组元素排序,并在主函数中将排序后的数组输出。
参考程序:
1.P193例7.9
2.P196例7.12
讨论并总结
1.数组元素作函数参数时,实参和形参间的传递方式是什么?
2.数组名作函数参数时,实参和形参的写法有什么不同?
结论1:
数组元素作函数参数时,实参与形参间单向值传递。
结论2:
数组名作函数参数时,实参和形参间发生地址传递;
在主调函数与被调函数分别定义数组,且类型应一致;
形参数组大小(多维数组第一维)可不指定,形参数组名表示地址;
实参写数组名,形参为数组定义。
学以致用
寻找你身边的一个实际问题,用到数组名作函数参数。
例如:
定义一个函数,实现10个同学身高的比较,从中找出最高身高,并返回到主函数中输出。
P193例7.9
三、函数的嵌套调用
问题4——问题3延续:
定义两个函数,分别求全班学生(假设10名学生)的某门课程总分和平均分,并将总分和平均分返回到主函数中输出。
问题4分析:
floataver(floatstu[],intn)
{inti;
floattotal=0;
for(i=0;itotal+=stu[i];
returntotal/(float)n;
}
求总分和平均分
intsum(floatstu[],intn)
{inti;
floattotal=0;
for(i=0;itotal+=stu[i];
returntotal;
}
问题4解决——函数嵌套调用
C规定:
函数定义不可嵌套,但可以嵌套调用函数
自定义aver函数:
#include
floatsum(floatstu[],intn);
floataver(floatstu[],intn);
voidmain()
{floatscore[10],average,total;
inti;
printf("Input10scores:
\n");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
total=sum(score,10);
average=aver(score,10);
printf("sumis:
%f,averis:
%f\n",total,average);
}
floatsum(floatstu[],intn)
{inti;
floattotal=0;
for(i=0;itotal+=stu[i];
returntotal;
}
floataver(floatstu[],intn)
{
floattotal;
total=sum(stu,n);
returntotal/n;
}
*自学内容:
问题5:
求三个数中最大数。
自定义函数mymax3()和
mymax2(),分别求出3个参数的最大值和2个参数的
最大值,在mymax3()中两次调用mymax2()求出3个
参数的最大值将值返回给主函数,输出该结果。
函数首部为:
floatmymax3(floatx,floaty,floatz)
floatmymax2(floatx,floaty)
问题5解决——函数嵌套调用
#include
floatmymax3(floatx,floaty,floatz);
floatmymax2(floatx,floaty);
voidmain()
{floatino1,ino2,ino3,max;
printf("请输入三个数:
");
scanf("%f%f%f",&ino1,&ino2,&ino3);
max=mymax3(ino1,ino2,ino3);
printf("max=%f\n",max);
}
floatmymax3(floatx,floaty,floatz)
{floatmax2,max3;
max2=mymax2(x,y);
max3=mymax2(max2,z);
returnmax3;
}
floatmymax2(floatx,floaty)
{if(x>y)
returnx;
else
returny;
}
四、函数的递归调用
1、定义:
函数直接或间接的调用自身叫函数的递归调用
直接递归过程:
间接递归过程:
2、说明
C编译系统对递归函数的自调用次数没有限制
每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起堆栈溢出
例:
用递归法求n的阶乘
(设n为小于15的正整数,由键盘输入)。
#include
intrfact(intn);
main()
{intn,fact;
printf("Inputaintegernumber(<15):
");
scanf("%d",&n);
fact=rfact(n);
printf("%d!
=%d",n,fact);
}
intrfact(intn)
{if(n==0||n==1)return1;
elsereturn(n*rfact(n-1));
}
练习:
对于以下递归函数f,调用f(4),其返回值为:
intf(intn)
{
if(n)returnf(n-1)+n;
elsereturnn;
}
A、10B、4C、0D、以上均不是
参考答案:
A
模仿练习
函数嵌套调用:
求三个数中最大数和最小数的差值。
自定义函数max()和min(),求出3个参数的最大值和最小值,然后定义函数dif(),调用max()和min(),求出3个参数中的最大值和最小值的差值,将值返回给主函数,输出该结果。
函数首部为:
floatmax(floatx,floaty,floatz)
floatmin(floatx,floaty,floatz)
floatdif(floatx,floaty,floatz)
#include
floatdif(floatx,floaty,floatz);
floatmax(floatx,floaty,floatz);
floatmin(floatx,floaty,floatz);
voidmain()
{floata,b,c,d;
scanf("%f%f%f",&a,&b,&c);
d=dif(a,b,c);
printf("Max-Min=%f\n",d);
}
floatdif(floatx,floaty,floatz)
{returnmax(x,y,z)-min(x,y,z);}
floatmax(floatx,floaty,floatz)
{floatr;
r=x>y?
x:
y;
return(r>z?
r:
z);
}
floatmin(floatx,floaty,floatz)
{
floatr;
r=xx:
y;
return(rr:
z);
}
随堂实践
1、在主函数中输入一个整数,打印它的平方值和立方值,求平方值和立方值分别用两个自定义函数完成。
参考程序:
#include
intpingfang(intx);
intlifang(intx);
voidmain()
{
intn,pf,lf;
printf("输入数n:
");
scanf("%d",&n);
pf=pingfang(n);
lf=lifang(n);
printf("%d的平方为%d\n",n,pf);
printf("%d的立方为%d\n",n,lf);
}
intpingfang(intx)
{
returnx*x;
}
intlifang(intx)
{
return(x*x*x);
}
2、在主函数中输入一int型数字,要求自定义函数求出这个数的每一位数字并输出,但每两个数字之间空一空格,如在主函数输入2003,则输出2003。
参考程序:
#include
voidprint(intx);
voidmain()
{
intn;
printf("输入数n:
");
scanf("%d",&n);
print(n);
}
voidprint(intx)
{
inti,j,a[10];
for(i=0;x!
=0;i++)
{
a[i]=x%10;
x=x/10;
}
for(j=i-1;j>=0;j--)
printf("%d",a[j]);
printf("\n");
}
五、变量的存储类别和作用域
问题6——变量存储类别
#include
voidprt();
voidmain()
{intx;
for(x=1;x<=5;x++)
prt();
}
voidprt()
{staticinty=0;
y++;
printf("%d",y);
}
输出结果:
12345
去掉static后的结果为多少?
11111
问题6分析——变量存储类别
C程序运行时用户占用空间分为三部分:
•程序区
•静态存储区
•动态存储区
变量存储类别:
•静态存储
——静态变量:
用static关键字表示
•动态存储
——自动变量:
用auto关键字表示
寄存器变量:
用register关键字表示
•自动变量:
用auto关键字表示
–如autointp,f;//p,f为两个动态变量
–在C中,默认的变量定义就是定义为动态变量
–即上述的p,f变量定义与intp,f;是完全等价的。
•静态变量:
用static关键字表示
在程序运行过程中一直有效。
–注意,如果静态变量出现在函数中,不会因为函数的调用结束而丢失这个变量的值
变量的作用域
内部变量与外部变量的作用区域是不一样的。
inta,b,c;//外部变量定义
main()
{
intx,y;//内部变量
x,y,f的有效区域
floatf;//内部变量
//其他语句…
a,b,c的有效区域
}
intsum(intn)//内部变量
s,i的有效区域
{
ints=0,i;//内部变量
//语句
}
总结
1.变量的存储类型
计算机的存储器分为内存和外存。
还有一个小小的临时存储器称为寄存器,用以存储一些反复被加工的数据。
C语言允许程序员区分是在内存还是在寄存器中开辟变量的存储空间。
2.变量的生存期
(1)在编译时分配存储单元。
这种变量的生存期为程序执行的整个过程,在该过程中占有固定的存储空间,称为永久存储。
(2)只在程序执行的某一段时间内存在。
比如在函数的执行过程中存在。
这种存储方式称为动态存储。
3.变量的作用域
变量的可用域也分为全局可用和局部可用。
C语言中,用“存储属性”来表示以上三个方面的属性,如表所示。
名称
寄存器变量
自动变量
静态变量
外部变量
存储属性
register
auto
static
extern
存储位置
寄存器
主存
生存期
动态生存期
永久生存
期
作用域
局部
局部或全局
全局
模仿练习
1、写出以下程序的运行结果:
fun(inta)//a为形参,自动型局部变量
{autointb=0;//b是自动型局部变量
staticintc=3;//c是静态型局部变量,初始化仅进行一次
b+=1;c=c+1;
returna+b+c;
}
main()
{
inta=2,i;//a和i都是自动型局部变量
for(i=0;i<3;i++)
printf("%d\t",fun(a));
}
2、写出以下程序的运行结果:
intsum(intn);//函数声明
inta=4,b=5,c=6;//外部变量定义
main()
{intx=1,y=2;floatf=3.0;
x=sum(10);
printf("x=%d,y=%d,f=%f\n",x,y,f);
printf("a=%d,b=%d,c=%d\n",a,b,c);
}
intsum(intn)
{ints=0,i;
for(i=1;i<=n;i++)s=s+i;
printf("s=%d,i=%d\n",s,i);
printf("a=%d,b=%d,c=%d\n",a,b,c);
returns;
}
讨论并总结
•1、函数的功能应该尽量保持相对独立还是依赖函数外的数据为好?
•2、怎样使一个函数具有更大的通用性?
•3、函数参数的值传递有哪些特点?
学以致用
•寻找你身边的一个实际问题,编写解决问题的程序,要求用到函数调用、参数传递。
•例如:
踢足球的时候,裁判要求换人,比如要用8号换下18号,请用函数模拟换人,并在主函数中调用。
作业——每人必做
将“控制流程”阶段完成的“小型计算器”功能改写为函数,并在主函数中调用,注意参数的类型定义及传参过程。
作业——选做
学以致用:
寻找你身边的一个实际问题,编写解决问题的程序,要求用到函数调用、参数传递。