段红义
摘要:函數是实现模块化程序设计的基础,是《C程序设计》课程教学的重点与难点内容,但是由于函数涉及内容比较复杂,知识点多,对于初学者来说理解、掌握并应用函数处理实际问题往往比较困难。针对我院应用型本科教学实际,结合笔者多年教学经验,在课堂教学中渗透模块化程序设计思想,教学过程中以案例教学为主,结合启发、提问、类比、图示、动画演示、上机实践等教学方法与手段,以达到让学生积极主动参与课堂教学,激发学生的学习兴趣,帮助学生更好地理解函数的教学内容,从而提高课堂教学效果。
关键词:函数;模块化程序设计;课堂教学;教学方法
中图分类号:G642 文献标识码:A
文章编号:1009-3044(2020)31-0119-03
函数是《C程序设计》课程中教学的重点与难点,同时它也是进行模块化程序设计的基础,对于培养学生建立并使用模块化程序设计思想处理复杂程序设计问题起着重要的作用。由于函数教学内容比较复杂,涉及的知识点较多,对于初次接触程序设计的学生而言,由于对函数知识理解掌握不够扎实,应用函数去处理实际问题的时候往往会遇到很多困难,如何让学生更好地理解与掌握函数的知识并利用函数来设计一些相对复杂的程序,就需要教师在教学过程中渗透“模块化程序设计”思想理念,讲明白函数的设计思路,设计方法,调用与参数传递的过程。本文以我院应用型本科教学实际为例,结合笔者多年的教学体会与经验,探讨通过由浅入深,循序渐进的方式,采取案例法、提问法、启发法、类比法、图示法、动画演示、上机实践等多种教学方法与手段,倡导以学生为中心的教学理念,让学生积极主动参与课堂教学,积极进行课堂互动,从而调动学生的学习积极性,提高课程的教学效果。
1 在函数教学中渗透“模块化程序设计”思想
为了提高学生进一步学习新知识的欲望与兴趣,引出函数的概念,先让学生了解模块化程序设计的思想。通过启发与提问相结合的方法引导学生进行思考,通过回顾前面学习过的知识,让学生进行思考当我们遇到一个大的问题时如果将所有的程序代码全部放在主函数中会有什么缺点?对于这个问题如果我们仍然利用前面学过的知识去解决,将程序的代码全部都放在主函数中,那么主函数将会变得越来越复杂,这样做程序的可读性比较差而且也不利于日后对程序进行修改、功能扩展。通过引出问题让学生去思考用什么样的方法去解决这个问题?这样我们就可以轻松引入模块化程序设计的思想了。模块化程序设计为我们处理大型的、复杂的问题提供了一种设计的方法,在大型软件的设计过程中无不体现这种设计思想。模块化程序设计就是将一个大的程序按照其功能的不同划分为若干小程序模块,每个小的程序模块完成一个特定的功能[1]。就好比我们玩的搭积木游戏,每一个积木可以看成一个模块即函数,我们用不同的积木来经过合理的摆放就可以搭建好一个游戏房子,对于我们所处理的一个大的程序而言,它就好比是一个大房子,该程序是由不同功能的子程序(模块或函数)所构成的,当我们把所有的子程序设计好以后,通过对它们的调用就可以完成程序设计。在C程序中,模块化程序设计通过函数来实现[2]。利用函数我们可以实现一次定义,多次使用的目的,达到程序的复用性。通过讲解模块化设计思想使学生进一步理解在处理大的复杂的程序设计问题时,我们应该采取什么样的设计方法,为学习函数的知识做好铺垫。
2 函数教学中主要教学方法的使用探究
为了让学生更容易理解与掌握函数这部分知识,教学过程中应遵循学生对知识认知规律的特点,讲授过程应采取循序渐进,由浅入深,由易到难,对不同的知识点采取不同的教学方法,并且在授课时与前面的知识内容进行有效的联系,下面以三个案例为主对教学中使用的主要方法进行探讨。
2.1 类比法在函数教学中的使用
在程序设计中有许多相似的题目与问题,当我们设计出其中的一个问题时,可以通过类比的方法设计出其他相类似的问题。
案例1:利用函数求1+2+3+…+n的值。
分析:这是一个简单的求和问题,在循环结构程序设计一章我们对该程序的设计方法做了重点介绍。可以使用C语言提供的三种不同的循环语句来进行设计。以for语句为例,可以写出其核心代码如下:
int n,i,sum;
sum=0;
printf(“输入变量n=”);
scanf(“%d”,&n);
for(i=1;i<=n;i++)
sum=sum+i;
printf(“sum=%d”,sum);
该程序比较简单,但是每次执行只能求一次累加和,不能重复使用,如在程序中要同时求解1+2+…+10,1+2+…+100的和,就需要重复书写除第一条语句以外的其他代码两次。我们可以使用函数来达到一次定义,多次使用的目的,根据函数定义的语法规则,对上面的程序段稍做修改,就可以修改为一个可以反复调用的函数。求1+2+…+n问题可以用下面的这个函数sum来实现:
intsum(int n)//函数头部,指出函数的类型,函数名,调用函数时需要的参数个数及其类型
{
ints,i;
s=0;
for(i=1;i<=n;i++)
s= s*i;
return s;
}
在main函数中我们可以反复地调用这个函数,只需给该函数提供不同的参数值即可。如有如下语句:
int s1,s2;
s1=sum(10);//求解1+2+…+10的累加和
s2=sum(100);//求解1+2+…+100的累加和
通过案例1的学习,引导学生在学习该例的基础上模仿写出如下实现方法与例1类似的函数,达到对知识的融会贯通,举一反三。
如求2+4+…+n,1+1/2+1/3+…+1/n等类似累加的数学问题。
这类问题的设计与案例1函数设计方法比较类似,也是借助循环语句进行处理的,对案例1的程序稍作修改即可写出这些函数。另外对于第二个函数的设计可以引导学生需要将累加语句改为s=s+1.0/n;才能得出正确的结果,另外还需要将函数的返回值与累加变量s修改为double类型。
2.2用图示对函数调用“虚实结合”的过程进行分析
函数设计完成后就可以使用该函数了,即通过调用函数来完成相应的操作,在函数调用时,对于有参函数来说涉及函数参数的传递,即需要将实参的值传递给形参,当形参获取到相应的值之后,就可以在函数体内对相关的量进行操作,这个过程称为“虚实结合”。参数传递分为“传值”和“传址”, “传值”过程相对比较简单,就是一个数据值的复制操作,是一个单向的操作,即实参把数值传递给形参变量,在函数体内对形参的操作不会影响到实参,这个过程学生比较容易理解,但是“传址”过程比较复杂,学生理解起来就有一定的困难了,因为“传址”过程涉及地址即指针的知识,为了让学生深入理解“传值”和“传址”过程,通过图示可以直观形象的标识实参与形参在函数调用过程中的数值状态。以案例2为例说明:
案例2:编写函数实现修改两个实参变量的数值。
先看下面的自定义函数swap1,分析为什么该函数不能实现交换两个实参的数值,其代码如下:
void swap1(int x,int y)
{
int temp;
temp=x;x=y;y=temp; //交换形参数据语句
}
int main()
{
int a=100,b=200;
swap1(a,b); //函数调用语句,使用普通变量作为实参参数
printf(“a=%d,b=%d”,a,b); //测试实参数据是否变化
}
分析:主函数中定义了两个整型变量a,b,其值分别为100和200,在函数调用时,以a,b作为实参,程序将把a,b的值传递给形参变量x,y,所以x的值为100,y的值为200,接下来执行交换语句,形参x的值变为200,y的值变为100,当函数调用执行完后返回到主函数时,执行打印语句得到输出结果a=100,b=200。本案例程序执行过程中实参与形参变量的值的变化用图1,图2所示:
通过该例我们可以总结出当用普通变量作函数参数时,只能够将实参的数值传递给形参,而不能通过对形参的操作来实现修改实参,这个参数传值称为单向的值传递[4]。
对本例做如下修改,将形参修改为指针参数,实参修改为地址,然后进行分析。
void swap2(int *x,int *y)
{
int temp;
temp=*x;*x=*y;*y=temp; //交换形参所指对象的值
}
int main()
{
int a=100,b=200;
swap2(&a,&b); //函数调用语句,使用地址作为实参,把a,b的地址值传递给形参
printf(“a=%d,b=%d”,a,b); //测试实参数据是否变化
}
分析:同样在主函数中定义了两个整型变量a,b,其初值仍然为100和200,但是在函数调用时,是把a与b的地址值作为实参传递给形参变量x与y,所以x的值为&a,y的值为&b,通过参数传递形参指针变量x指向主函数中的变量a,形参指针变量y指向主函数中的变量b,接下来执行自定义函数中的交换语句,*x与*y的值进行了交换,因为*x为指针变量x所指的对象即为主函数中的变量a,同理*y为主函数中的变量b。同时需要注意虽然*x与*y的值发生了变化,但是x与y的值却没有变化。当函数调用执行完后返回到主函数时,执行打印语句得到输出结果a=200,b=100。修改后的程序执行过程中实参与形参变量的值的变化用图3,图4所示:
通过修改后的例子我们能够发现并总结出如果要在自定义函数中实现修改主调函数中的变量,可以使用指针变量作为形参,使用普通变量的地址作为实参,这样就可以间接地实现利用形参对实参的修改,故称为“双向数据传递”。
2.3在递归函数设计中数学思维及动画演示的使用
递归函数是《C程序设计》课程中的一个难点,如果定义函数时在函数体内调用自定义函数本身,执行时形成递归调用,称该自定义函数为递归函数。在讲授递归函数内容的时候,可以结合數学递推思维来描述递归问题。
案例3:编写递归函数求n!。
根据高中学习过的知识,启发学生求解n!可以写成如下的数学递归公式:
如果用函数double fac(int n)表示n!,其中fac表示函数名,整数n表示形参,通过该公式发现,求解n!有两种情况(1)当n=0或1时,n!=1,即fac(1)=1或fac(0)=1即函数返回值为1;(2)当n>1时,n!=n*(n-1)!,即fac(n)=n*(n-1)!,函数返回值为n*(n-1)!。显然求解(n-1)!仍然需要调用该函数自身即调用fac(n-1),即这是一个递归问题。
根据分析并按照函数定义语法规则,可以写出如下递归函数:
double fac(int n)
{
if(n==0 || n==1)
return(1);
else
return(n*fac(n-1));
}
在设计递归函数时,应给学生特别强调递归函数设计一定要满足两个要素,一个是能够根据题目写出相应的递推公式,另一个是递归函数调用的结束条件,二者缺一不可,否则会造成设计上的错误。
递归函数的调用执行是一个非常复杂的过程,学生对这个过程理解起来有很大的难度,为了让学生更好理解“回溯”与“递推”,在教学中采用动画来演示其执行的过程,通过动画演示可以形象直观的表示递归函数的调用执行过程。动画演示在教学过程中具有形象、生动、直观且感染力强的优势,能清晰地展现出需要强调的主要教学内容,轻松化解教学难点知识,使复杂的教学过程得到简化,同时也可以减轻教师工作量[5]。
3 结束语
通过函数我们可以实现模块化程序设计,学习使用函数对于培养学生处理解决大的复杂的问题具有极其重要的作用,所以在教学中,让学生掌握好函数的知识非常重要,教学应以学生为中心,采取多种方法与手段,充分调动学生的自主学习意识,学习兴趣、学习积极性。本文只介绍了函数教学中使用的其中的几种方法,这些方法不是孤立使用的,在教学中我们可以将这些方法进行有效的融合,多使用形象,直观的教学方法,这样可以使教学中的难点问题简单化,便于学生理解与掌握,有助于课堂教学的提高。
参考文献:
[1] 赖均,等.软件工程[M].清华大学出版社,2016.
[2] 谭浩强.C程序设计(第五版)[M].北京:清华大学出版社,2017.
[3] 吴登峰,等.C语言程序设计[M].北京:中国水利水电出版社,2015.
[4] 赵娟,樊超.C语言函数参数传递规律[J].现代电子技术,2012,35(4):55-56.
[5] 彭冬生.动画演示在《材料科学基础》教学中的应用[J].科技创新导报,2013,10(9):158.
【通联编辑:代影】