面向初学者的C语言编程方法研究
2018-01-04李欣潼
李欣潼
摘要:C语言是一门十分重要但对初学程序设计的同学来说又是相对难学的一门计算机语言。从初学者的角度出发,按照分析问题,算法设计,编码实现及程序运行几个步骤,说明了学习C语言的方法。论文以二元一次方程组的求解过程为案例,首先详细地论述了问题分析的方法,然后从C语言学习时初学者难于掌握的运算符使用、循环控制、自定义函数、数组及指针几个方面详细地说明了分析和编码实现方法,最后说明了上机实现的方法和重要性。
关键词:初学者;C语言;二元一次方程组;问题分析;程序实现
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2018)29-0113-04
Abstract: C is one of the very import program design language.Oriented beginner, this paper explains the method of learning C language according to the analysis of problems, algorithm design, coding implementation and program running steps. Taking the solving process of binary first-order equations as a case, this paper discuss the method of problem analysis at first, and then illustrates the method of coding at the aspects of operator use, loop control, custom functions, arrays and pointers which are difficult for beginners in C language learning. Finally, it explains the method of computer practice.
Key words: beginner; C Language ;binary first-order equations;problem analysis;computer practice
为响应“计算机要从娃娃抓起”的号召,我国各地中学均开设了计算机相关课程。程序设计在启发中学生的想象力和创造力,提高数学分析和逻辑思维能力,增强理解和解决问题的能力等方面很有作用,因此已经成为中学生必修的一门课程。C语言作为一门应用最为广泛的计算機语言之一,是许多高中开设的计算机程序设计类课程,同时也成为信息学奥林匹克竞赛的官方语言之一。C语言是一门面向过程的高级计算机语言,它语法灵活,编程简洁、紧凑;特别适合于模块化程序设计,层次结构清晰,且功能强大,即适合开发应用软件,也可以开发系统软件,因此应用领域特别广泛。但由于它运算符丰富,语言限制不很严格,程序设计的自由度大[1][6],针对初学程序设计的中学生来说入门很困难,不容易掌握。本文根据自己学习C语言的感悟,将程序设计过程为主线,通过‘问题→想法→算法→程序的问题求解过程[2] ,详述学习C语言程序设计的方法,以希望能对初学者有所借鉴。
1 学习第一步:从分析问题入手,由简到难设计解决问题的步骤
学习程序设计的目的归根结底是要利用计算机工具去解决人们日常的生活、工作、学习和娱乐等遇到的问题。问题的解决需要确定的步骤和方法。对于复杂的问题要分析问题的层次和功能模块的划分,而对于简单的问题,只要确定已知什么要求什么怎么求即可,初学者学习程序设计之时,应该从学生比较熟悉的简单问题入手,了解问题的具体内容(分析问题),具备什么样的条件(已知什么?),需要解决什么(要求解什么?),然后用自己具备的知识选择适当的解决方法(选择设计算法),最后按照计算思维过程根据算法来设计步骤,实现编程。中学生学习生活中,最为熟悉的是数学问题,因此可以选择一些数学题目作为初始编程案例,题目难度从简单过渡到复杂,在初学者易于介绍的状态下逐步掌握程序设计的过程。本文以“求解二元一次方程组的解”作为全篇贯穿案例,介绍学习程序设计的过程。
①分析问题:
经过分析,清楚待求解问题是对给定的二元一次方程组求它的解。针对初学者,可以先把问题设计得简单些:只求有唯一解的二元一次方程组的解。这样可以明确地是给定的方程它只有一个唯一解,问题和目的更为确定。结合学生的知识储备,知道二元一次方程组是由两个方程构成,每个方程由两个待求的未知数及未知数的系数和常数项构成。求方程组的解需要利用消元法、代入法等求解。
②确定已知条件:
对于简单的问题,大多是已知什么,求解什么,怎么求问题。经过第一步的分析,明确了要解决的问题后,要先考察的是已知什么样的条件,比如已知哪些数据和条件。当明确了已知条件并将其表示清楚,才可能进一步利用它们去求解。需要注意的是,对于已知数据,要通过分析数据的特点、表示的内容来确定数据的类型,然后用合适的符号对已知数据进行表示。已知数据抽象成了符号,便可以方便地在算法中使用。本例中是给定一个简单的有唯一解的二元一次方程组对其求解,它的已知条件应是两个方程系数及常数项。可以按照数学课中使用的方式暂时用a1,b1,c1来表示第一个方程的已知条件;用a2,b2,c2表示第二个方程的已知条件。如果它们已知并且确定了就可以利用它们在算法中完成求解。
③确定要解决的具体问题
这种情况对于初学者,一般是要解决求什么的问题。求解的问题可能是完成某种操作,也可能是求得一些数据结果。求解的内容不一样,设计的算法也不同,因此明确求什么样的结果将决定采用什么样的算法。本文要求解二元一次方程组的两个未知数的解,求的是数据,设计的算法就应该与计算有关。如果要求解的是数据,那么同已知一样,应将结果用符号表示出来,以便于设计算法时应用。本例的求解问题是方程组的解,把它们表示为x和y。
④设计计算法方法即算法
分析问题之后,明确了已知和待求解问题,接下来就是怎么求解的问题,也就是用什么样的方法来根据已知求未知。这个过程是要在编程者掌握了一定的数学、生活常识和计算机计算等知识和常用算法后,结合具体的问题选择相应的算法来实现。这一步骤在整个编程过程中都是比较难的,只有有了一定的基础和经验,才能更正确和合适地设计算法。但对于初学编程的同学,初始接触的问题不难,是可以结合自己的基础来确定算法的。需要特别注意的是程序设计设计的是程序,而程序是有着严格的顺序和过程的,在设计问题的算法时,一定要注意计算的顺序。算法中应用符号化的已知及待求数据,会让算法更为清晰明确。
⑤描述算法
通过算法可以看出清晰的问题计算过程和方法。
2 学习第二步:用C语言程序描述算法
确定好算法后,要用计算机程序来描述问题。计算机程序是选择不同的计算机语言,按照相应的语法规则来程序化的算法。C语言是一种编程语法灵活,代码简洁、功能十分强大的计算机语言,但其运算符丰富,语法格式灵活,对初学者来说掌握起来并不容易。因此本文采用由简至繁的方式让学生循序渐进地掌握C语言的语法规则。
用计算机语言描述算法,首先要清楚所采用语言的程序结构。C语言是以函数为单位的,函数格式也比较简单,很容易记忆,本文不再多述。
本文中从只有一个函数且函数内部只是由顺序结构构成的最简单C语言程序开始,循序渐进结合第二部分内容来说明C语言程序的编程方法。下面依然利用二元一次方程组的求解问题说明C语言程序设计的方法。
2.1数据及简单程序
C语言数据类型丰富,运算符及表达式种类繁多,这说明C语言表达能力强,但因规则繁杂,对初学者来说掌握不易。初学之时,只要掌握C语言标识符的概念,整型、实型、字符类型基本数据及常用算数运算符和赋值运算符即可,不必过多记忆。
计算机工作原理是只有将程序和数据存入到内存中,计算机才能执行,所以内存变量的概念是这部分的重点内容。前文分析中已知数据、求解数据及算法设计时所借助的数据都必须存放在内容变量中,所以要在分析问题时确定这些数据所代表的数据形式以及大体范围,这样就可以在设计程序时将它们首先声明好。
本文案例中已知的六个数据表示的都是数值,可以是整型也可以是实数,但是待求解的数据在算法中需要用到除法运算求解,因此为了少损失精度,应务必将其定义为实数。所以数据定义为:int a1,b1,c1,a2,b2,c2; float x,y;。数据声明过后,就可以利用这些数据完成运算了。初学时运算符学习中特别注意除号(/)和求余符号(%)以及赋值号(=)的使用,其他均与数学课中的使用相似,不必过度探讨。同时掌握基本数据的简单输入输出函数的scanf和printf的使用也是必需的。这样就可以实现简单的数学计算类程序的编写了。至此,本文中二元一次方程组的解相应的程序就可以完整地编写出来(完成程序略)。只记住少量的规则就能够描述简单程序对初学者来说是一个学习动力,并能鼓舞和激励他进一步学习。
2.2循环控制
顺序结构和选择结构在初学者学习时难度均不大,接受容易。选择结构中只要牢记if语句的语法和常用的关系和逻辑运算符的使用,大多掌握起来并不困难。但循环结构是初学者学习C语言时继运算符和表达式后的又一个难点。循环结构程序设计是C语言程序设计中最重要和最难掌握的基本结构[3]。C语言的循环结构可以由while、do while和for语句实现。三个语句各有其特点,但均可以完成任何的循环控制。初学者开始只要掌握while的语法规则,当清楚并掌握了while语句的使用,其余两个自然就迎刃而解了。
除了循环控制的语句,学习者还应该明白循环语句的用处。在简单问题中循环结构有两个作用:①控制重复某些计算的次数(次数≥2);②符合一定条件后重复执行某些计算,直到条件不满足为止。通过对问题的分析,只要在算法中出现上面两种情况,就一定要用到循环结构。对于循环结构的算法实现,两种情况都要从以下四个步骤考虑:循环结构执行之前的初始化问题;循环条件的控制问题;需要重复执行的内容;循环控制条件的修改。熟记这四方面的使用,循环结构就可以万无一失了。下面还以二元一次方程组求解来详细说明。在分析问题基础上按照循环的两种情况增加题目难度:①求n个不同的二元一次方程组的唯一解(n代表个数,比如n=5);②判断已知条件,若输入的两个方程的未知数系数对应成比例,使得二元一次方程组无唯一解,即继续输入,直到输入的数据能够使方程组有唯一解为止。按照问题分析:第一种情况是重复执行多次,计算需要一次次完成,只要在问题分析的算法中加入对次数的统计和判斷即可;第二种情况对输入数据要按照数学上一样的判断方法,由于“对应成比例”的判断易产生误差,所以改为对应乘积的比较更合适。具体实现从四个步骤说明两种情况。
1)循环结构执行之前的初始化问题
第一种情况在原有算法中,加入一个次数统计变量n,它初始可以从任意一个数值开始,一般习惯上从0或1开始,本文计从1开始,即n=1;
第二种情况是根据输入的二元未知数的系数来判断,因此就是输入的a1,b1,a2,b2的值,即input a1,b1,a2,b2。
2)循环条件的控制问题
第一种情况求五个二元一次方程组的解,就是重复执行五次求解,那么循环控制条件就是在次数没超过5次之时均要计算,则循环控制可以为n≤5;
第二种情况系数成比例就要重复输入,因此控制条件是判断a1b2-a2b1是否为0。
3)需要重复执行的内容
第一种情况重复的是方程组解的多次求解,因此算法2中的①②③④步都需要重复;
第二种情况是对输入数据的判断,因此重复的是输入数据语句,即步骤①。
4)循环控制条件的修改
第一种情况循环控制条件是执行一次循环就增加一次次数,所以应为n=n+1;
第二种情况循环是因为输入的数据使得方程组没有唯一解,那就需要重复输入,所以循环控制条件的修改是再次输入数据,即scanf(“%d%d%d%d%d%d”,&a1;,&b1;,&c1;,&a2;,&b2;,&c2;);常数项也一同输入吧。
通过上面的问题和算法分析,两个情况下程序在算法1基础上,确定为图2和图3。
2.3 C语言函数
在C语言应用中,模块化程序开发的方法是必须的。函数使用是实现模块化程序必不可少的方法[5],函数的使用有诸多优点:可以增加程序的可读性、可以实现代码重用、可以让程序结构更清晰等,但自定义函数的使用对于初学者来说也是特别难掌握的。学习时最应该让初学者掌握的是什么时候用函数和函数应该如何定义。什么时候用函数呢?简单地理解就是程序中有特定功能的独立部分、在程序中要被多次执行的部分,这些地方都可以用作自定义的函数。那么如何声明函数呢?首先要知道函数的功能,其次要清楚函数的形式参数。函数的功能决定了函数的任务:它由哪些代码实现,它的功能是求一个数还是完成某种操作;而函数的形式参数就是函数功能是被哪些数据决定,这些决定函数功能的数据就应该是函数的形式参数。了解了这些初步的简单函数声明就可以实现了。
比如二元一次方程组求解中,判断方程组是否有唯一解部分就是独立于其他部分的,可以用自定义函数实现。它的功能是判断是否有唯一解,这个判断需要由哪些数据确定呢?是两个方程的未知数系数,那么方程的未知数系统就是形式参数。函数的功能是判断结果,那么可以约定如果有唯一解函数的结果即函数值是0,如果没有唯一解,那么函数值就是1。根据这样的分析,可以将函数定义为图4。
此例中对二元一次方程组的求解,也可以编写成自定义函数。函数的功能是求解二元一次方程组的解,实现功能的代码是独立的。函数的功能需要根据方词组的未知数系数及常数项来决定,那它们就是这个函数的形式参数。因函数的功能不似图4的函数是只求一个值的,那么功能的实现需要结合其他的C语言知识来实现,比如解用两个全局变量来实现,函数无需返回值(函数的程序略);也可以将结果通过两个特别增加的形式参数传值带回到主调函数中(将在2.5中详述)。
2.4数组的使用
数组的作用是为了管理和使用内存的批量存储单元。它的使用拓展了C语言的应用范围,比如批量数据的排序,以及有关利用矩阵的计算等应用,相应地也增加了分析问题的难度和对应算法的复杂性。初学者要了解何时适合使用数组、数组的简单使用方法、特别是数组下标的表示即可,熟练掌握了之后,再考察难度较高的应用和算法。
从二元一次方程组的求解,了解已知数据有6个,待求数据有2个,都不很多,用数学课上的常用符号——英文字母(x,y)及英文字母加数字(a1,b1,c1等)表示就可以分得很清,哪个符号是哪个未知数的系数,哪个是常数项不会搞乱。但是当未知数多(比如≥3)时,再用这样的符号,对应起来可能会比较麻烦。比如n个未知数n个方程的方程组,即使是n个常数项都不知道用哪些字符表示能分清楚到底是第几个方程的,更别说使用了。但是如果应用了C语言的数组,可以用数组的下标表示是第几个方程的常数项,并且下标能够灵活变化,一个符号可以统一代表所有方程的常数项。数据一旦用抽象符号表示,可以更易分析算法。这样n个常数项可以用一个一维数组来表示。常数项若都是int类型,那么常数项就可以用int c[n]; 声明(n为符号常量或是有确定值的整数,代表有n个方程)。同样的每个方程由n个未知数,那么每个方程的未知数系数也可以用一个一维数组定义,比如int a1[n]; ,而有n个方程组了,那系数中的每一个都需要再加一维,这样便构成了二维数组,可以定义为:int a[n][n];。这样知道了数组何时使用,而且引进了下标,对批量数据的位置和表达容易了也通用了,问题分析和算法的确定也更容易,数组在C语言编程中使用就有了基础。数组的使用不要急,要从简单的一维数组实践开始,特别注意数组下标的范围、变化以及在批量数据中的位置,循序渐进才能真正掌握。
2.5 指针的使用
指针是C语言的重要数据类型也是C语言的精髓和特色[6]。指针的使用可以提高C语言程序运行的速度,可以提高内存的使用效率,也可以间接地访问内存变量,从而扩充程序的功能。但是指针也是比较难掌握的内容。
建立在应用基础上的C语言学习,是要按照由简至难,从陌生到了解,再到熟悉,最后到完全掌握的过程学习,所以依然可以从简单的简单变量的间接访问开始,了解和体会了指针的基本功能,其他的作用就会慢慢地接受。
2.3节中可以把二元一次方程组求解过程声明为自定义函数,方程组的解可以“通过两个特别增加的形式参数传值帶回到主调函数中”,那么我们在主调函数中的求解x,y的值,可以利用被调函数多增加的这两个特别的形式参数计算传回。由于C语言的函数无论被调函数还是主调函数都是相互对立的,它们之间的联系就是通过调用联系。调用时主调函数首先要完成实参将值传给被调函数的形式参数,借用这个机会,如果实参传给对应形参的是值,那么形参可以利用这个值完成计算;实参如果传给对应形参的是地址,那么对应的形式参数获得实参的地址,就可以在自己的函数内部完成对对应实参的访问,这就是间接访问。具体地定义求二元一次方程组的解的函数见图5:
实参的调用语句为:solve(a1,b1,c1,a2,b2,c2,&x;,&y;);。调用时实参a1-c2是传值给对应的形参,对应的形参与之对应关系是单向赋值,形参只从实参那里得到了值。而实参x,y传给对应形参指针变量px和py的是地址,当获得了实参的地址,指针变量就可以通过内存地址间接的访问对应的实参,图5程序中*px的值就是x的值,*py就是变量y。这样被调函数通过被传地址的指针变量间接地为主调函数范围内有效的变量x,y赋过了值,这就是间接访问。这个明白了再了解了指针移动等运算,指针部分的掌握也就不成问题了。
这部分学习建立在应用基础上,以任务作为驱动,让C语言学习过程中的几个难点部分从简开始,易于让初学者接受和掌握,这样学起来会更有信心。
3 学习第三步:上机实现
C语言程序设计的学习,理论分析、编码与上机实践同等重要[7],程序完成了但不在机上运行是毫无意义的。所以程序在计算机上运行正确无误才是任务的最终完成。初学者一定要重视这个环节。如果运行错误要仔细分析错误原因,若要弄清楚需后退回到第一步和第二步再做修改,直到运行无误为止。无论是问题的分析还是算法的设计,抑或是编码时的C语言语法,上机运行可以实现对前面的学习检验同时更有效地丰富经验。上机实验时,熟悉所用工具的开发环境也是很重要的。当前C语言的编程大多采用合适的集成开发环境,比如dev cpp及codeblocks等,无论哪一种熟练掌握它的操作,特别是出现错误时的错误提示、调试和分析程序运行的手段,对于初学者都是很重要的。总之计算机语言的学习理论和实践同等重要。
4 结论
学校讲课及学生学习编程时,都是从学习语法开始讲授或是学习,学习之初学生就开始背诵语法。语法是语言的基础和规则,当然很重要,可以说没有掌握语法,就无法编写出正确的程序。但是对初学者来说,机械地背诵语言,很容易忘掉且不容易牢记。本文从初学程序设计的学生出发,论述了从分析问题开始,以任务驱动为主要方式,让学生掌握编程的步骤:分析问题、设计算法、确定步骤,并形成习惯。论文再以C语言学习时的难点为内容,采取案例的方式说明克服它们的方法,目的是希望初学者从简单问题开始,循序渐进使学生在潜移默化中学会程序设计。
参考文献:
[1] 倪瑞晓.C语言编程技术的分析研究[J].计算机技术与发展,2009,19(12):251-254.
[2] 胡明,王红梅.程序设计基础:从问题到程序[M].北京:清华大学出版社,2011.
[3] 裘宗燕.今天的C程序设计课教什么,怎么教——兼议《从问题到程序》的修订[J].计算机教育,2012,13(7):24-32.
[4] 李娟,张燕.C语言循环结构教學的设计与实践[J].计算机教育,2018(3):89-91.
[5] 苏冬娜,高俊涛.基于C语言的计算机编程技术分析[J].信息与电脑, 2016(18):54-55.
[6] 张蕾.基于项目化教学的"C语言程序设计"课程改革[J].计算机教育,2013(2):17-20.
[7] 夏秋菊.在C语言教学中如何培养学生的动手编程能力[J].新课程学习:下,2013(2).
【通联编辑:王力】