董巍
(湖北文理学院计算机工程学院,襄阳 441053)
C 语言广泛用于系统软件、单片机应用的开发之中;它是大学计算机类专业程序设计课程的首选教学语言;在TIOBE 网站每月公布的计算机编程语言排行榜上,其一直占驻第一或第二名的位置[1]。这些,充分体现了C 语言的生命力强和应用范围广的特点。
C 语言作为计算机类专业教学的第一门编程语言,教学目的主要有两点:一是对程序设计基本概念、原理、方法的了解、掌握和运用,二是对程序编码与程序调试能力的训练和培养。即承担着编程启蒙和入门、进而为学习其他编程语言、后续专业课程提供专业术语和编程技能的服务作用。由于其基础性和重要性,针对C语言程序设计课程的教学内容、教学方法和教学手段的研究层出不穷、方兴未艾。在中国知网,以“C 语言”、“教学”为主题搜索到的5000 多条文献中,多是关于教学方法、教学模式的研究,而针对课程知识点的相互关系和深度应用的研究则比较少。因此,本文从C 语言的几个重要知识点的应用出发,结合教学规律和教学方法展开探讨,帮助提高该课程知识的教、学、用。
学习具有四个阶段:识记、理解、意识、悟性。即是我们常说的了解和记忆、理解和掌握、熟悉和应用、拓展和创新,它们呈现逐级提升的状态。
识记是学习任何知识的第一阶段,是高楼大厦的基石,学生也会花费大量的时间进行知识的识记。
大量的事实表明学生对识记性知识掌握、直接运用的效果并不好。例如:讲述了标识符的命名方法、特别是命名要遵循“见名知意”的原则之后,学生在给程序文件、文件夹命名时仍习惯于使用数字或汉字作为名称,程序中变量的命名仍五花八门、晦涩难懂。
一些具有丰富教学经历和经验、对教学内容有深刻理解的教师,可以直接传授给学生第二级的信息——理解。
C 语言是学生接触的第一门程序设计语言,其包含的概念、原理、方法、技巧等呈现多繁杂的特点。因此,提出了“语法够用、重在算法”的观点,且践行着“化繁为简、循序渐进”的教学思想。例如:在讲述scanf、printf 函数时,强调格式控制符的类别和个数必须与变量的类型和个数一致,以避免键盘输入数据的非法而导致变量获取值的错误、输出时数据的存储格式转换而导致的乱码;再例如:对“if(表达式)”,其标准的样式是“if(exp!=0)”,由于C 语言的灵活性,常将其简写成了“if(exp)”;而对于“if(!exp)”的理解,可将其直接补充为“if(!exp!=0)”、再将两侧的“!”同时去掉、则演变成了“if(exp==0)”,这样的推导、理解使得学生感觉到豁然开朗,既简洁又直观。
经历了认知、理解、练习、思考、总结之后,真正做到融会贯通、形成意识,则学习已经进入到了一定的高度和境界,也就是培养出了计算思维。这不是老师所能直接完成的任务,即意识只能训练、培养,不能传授。通常,在讲述循环结构、数组、函数时,一般会讲解大量的、典型的例题,再配以大量的练习题,以此来巩固基本概念、归纳基本方法、总结解题经验和技巧、扩展应用范围等,更重要的是实现数学思维向计算思维的逐步转变和培养[2]。
珍贵的不是那些死记硬背的知识,而是创造知识的悟性。对大众来说,主要是运用所学知识解决实际问题,即应用;对少数悟性高的人来说是创新。老师所能做的只能是启发、诱发、激发、开发。应运而生的是在大学广泛开展的创新创业教育、学业导师制等。
C 语言程序设计课程中存在大量的概念和专业术语,既需要严谨的书面语言对其进行定义、也需要通俗易懂的口头语言对其进行讲解;既需要理解其字面意思,更需深刻理解其内涵和外延。
例如,数组是“一批类型相同、名称相同的元素组成的有限序列”,这句话体现出了数组的类型、名称、容量、有序(值及其顺序)等意思,因此,在编程时声明和定义一个数组则分别需要紧抓其三、四要素[3];数组的应用则紧紧围绕其四要素展开,特别是数组元素的值和实际元素个数,且数组实际元素的个数可能是动态增长的。重点练习的题目有求一个整数的所有因子、所有质因子,使用数组模拟集合的并较差补运算等。这些题目既包含了对概念的深刻理解、也包含了基本的算法。
再如,对函数首部“三要素”的理解、确定和使用,特别是函数的类型、最重要的是函数参数的个数和类型的确定,因为通过函数调用只能返回一个值,要想得到多个值就必须通过函数的参数来完成、且参数必须使用指针型参数[4],这是教学的重点和难点。
函数应用的目的在于程序结构化、模块化和重用性。初学者可能更习惯于整个程序只有一个main 函数,这样的话,略微复杂的程序则繁琐冗长、结构不清晰、功能不明确,或者函数中包含有数据的输入输出,或者大量使用全局变量,或者所有函数都是空类型而没有返回值……,这些都会降低程序的可读性、结构化、模块化、重用性等。解决办法是采取“三步曲”的模式进行讲授:主函数中只由三类语句构成,第一是输入、第二计算、第三是输出,第二中的计算自然而然必须使用自定义函数来实现,且需根据计算的复杂性进行再分解。经过一段时间的训练逐步建立“三步曲”的思想,从而逐步建立函数思维。
再如,链表是C 语言学习的难点、也是重点,若对链表操作中几个赋值语句能很好地理解,则能达到事半功倍的效果。假设有如下的赋值语句:
这些赋值语句,从物理上看、或者说从右向左看是赋值,是把一个地址值赋值给另一个指针变量或指针变量的指针域;从逻辑上看、或者说从左向右看是指向,是一个指针指向另一个结点;若赋值号左边是某个变量的指针域则表示是链的连接[5]。这样的理解将使得复杂的指针运算变得形象直观。对这几个赋值语句的正确理解、运用,将会对链表操作、更是对《数据结构与算法》课程的学习起到事半功倍的效果。
模运算是一个重要的运算符,其典型应用有:分离一个整数各数位上的数字,数学黑洞问题,判断一个整数是否为素数,求一个整数的因子,输出某年某月某日是星期几,仿照电脑上日历的样式打印万年历,根据“三天打鱼两天晒网”的规则判断渔夫某天该干啥[6],多个空瓶换汽水的问题,等等。
位运算在解决实际问题的应用中具有更大的实际意义。如位与运算,本意是对两个整数的对应二进制进行与运算,从而得到一个新的整数;物理意义则是屏蔽或析出一个整数某个二进制位上的值。例如:判断一个整数是奇数还是偶数,常使用的方法是模运算,而使用位与运算则显得更为“高大上”;在根据几句话判断几名嫌疑人究竟哪些是罪犯的推理题中,可以使用一个整数的几个二进制位来代表几名嫌疑人,即将嫌疑人的一组状态映射到一个十进制整数的固定二进制位上[7],则是位运算的深度应用。
在C 语言程序设计的教学中,假设法、枚举法、筛选法是常使用的方法和技巧。
例如:三个数求最大值、通过数组求最大值、进而推广到通过一个循环同时求解一批数据中的最大值和最小值、最后拓展到选择排序,“假设第一个数就是最值”这一思想体现得淋漓尽致;使用数组筛选出素数、约瑟夫问题、红黑球的放置问题等等,既体现了筛选法的应用、又显现了整数(或编号)与数组下标之间的映射[8]。
上面这些基础性的题目,既有多个知识点的综合应用、也呈现出了从简单到复杂的递进关系、更有问题的追根溯源(雏形)。因此,不论是教师、还是学生都需要不断的分析、思考、总结、探索。
对于基础型课程,在教学中运用最多的是案例式、递进式、设问式教学等,还有翻转课堂正不断兴起和大量运用。
深入研究课程内容,挖掘知识点之间的相互关系,创设更多更好的基础性、综合性、应用性的题目,因地制宜地运用多种教学方法和手段,因材施教地开展教学,把教学重心转移到“五个突出”上,即突出理解基本概念、突出掌握基本技能、突出计算思维养成、突出核心知识点把握、突出编程能力训练,从而推动本科院校教学水平和教学质量的不断提高。