现行的多数C语言教材有太多的误区,不仅不能给读者提供有效的学习线索,还常常“误导”读者,于是,“死记硬背”便成了学习C语言的唯一选择。本文以拙作《新编C语言程序设计教程》(清华大学出版社出版,配套视频zeq126.56.com)为基础,探讨了C语言的研究性学习。
C语言的知识点有:
1. C语言与计算机的关系
2. 表达式的求值
3. 逻辑运算及选择结构
4. 算法及循环结构
5. 数组的作用及准确理解
6. 函数的作用及准确理解
7. 指针的作用及准确理解
8. 自定义数据类型及文件
这几部分相辅相成,构成了一个有机的整体。分析如下:
六、函数的作用及准确理解
C语言用函数组织代码。程序和函数通过将用户的输入转换成用户需要的输出实现某种功能,本质上都是从输入到输出的映射(显然这里的映射仅指“对应关系”。百度百科:在数学上,映射则是个术语,指两个元素集之间元素相互“对应”的关系。数学上严格意义的映射要求“对应的唯一性:定义域中的一个元素只能与映射值域中的一个元素对应”,最初的函数只能通过函数的返回值输出数据,还勉强算数学上的映射。),因此,同样的功能既可以用程序实现,又可以用函数实现,也就是说程序可以改为相应的函数,函数也可扩展成程序(程序似乎就是一个main函数)。
递归函数是个奇迹,那样自然那样优雅地模拟了递归算法。(程序是算法的模拟,算法是我们解决问题的方法,编程的关键在于我们这个超级计算机。)
本章的重点:
1.函数的作用。
2.自定义函数的实现过程。
3.函数调用的特点。
4.理解三种函数操作:函数定义、函数声明和函数调用。
5.变量的作用域对函数封闭性的影响。
6.关键字static的作用。
7.一维数组作为函数参数时的特殊之处。
8.递归函数的用法。
9.常用库函数的使用。
10.用函数组织程序。
本章的难点:
1.理解函数的传值调用。
2.自定义函数的实现。
3.全局变量的正确使用。
4.随机数函数的使用。
5.递归函数与递归算法的关系。
6.正确使用库函数。
7.函数与程序的关系。
(一)函数定义
重点:
1. 函数定义分两部分,理解各部分的作用。(首部表明函数的功能;函数体完成从输入到输出的映射。)
2. 怎样实现自定义函数。(第一步根据功能确定函数的首部;第二步完成函数体)
3. 单个函数在VC6.0中可以编译吗?(只能通过编译检查函数中的语法错误。)
4. 把例7-1至7-4实现为程序,体会相同功能的程序与函数的异同。(算法相同。程序的输入用scanf函数而函数的输入用参数;程序的输出用printf函数,而函数的输出用返回值。)
讨论:
1. 使用函数时一定要知道函数的函数体吗?
2. 函数有何作用?(把功能包装成函数就可以方便地重复利用这个函数,正如printf函数和scanf函数所示。)
(二)函数的调用与声明
重点:
1. 发生函数调用时,程序如何执行?
2. 函数调用的语法。(注意:“函数调用”在程序中可以看作是其“返回值”;如果没有返回值,则其作用仅是执行一次函数体。)
3. 通过例7-5切记函数传值调用的特点。(函数调用执行时可能发生两次类型转换。实参向形参赋值时,如果类型不匹配则会发生类型转换;通过return语句返回函数值时,如果其类型与函数定义的返回值类型不一致则会发生类型转换。)
4. 如何通过文件包含的方式使用已定义好的自定义函数?
5. 通过例7-7体会函数的作用。(重用代码提高编程效率;包装代码提高程序的可读性。)
6. 理解函数声明的作用。通过例7-8再次体会函数的传值调用,并分析其给函数带来的影响。(当实参为变量时,被调用函数只能使用变量的值,而不能通过形参修改相关变量的值,也就是说,函数无法影响其它函数。问题:能在被调用函数中直接使用其它函数中的变量吗?)
(三)作用域
重点:
1. 何谓变量的作用域?它给函数带来了什么影响?(变量的作用域给函数带来了封闭性。函数不能使用其它函数中的变量,同时其变量也不会被其它函数使用。函数的封闭性是指相同的实参总能得到相同的返回值。)
2. 如何看待函数的封闭性?全局变量对此有何影响?(函数应该具有封闭性,只有如此函数的使用者才能放心地使用;也只有如此,函数才能在多个地方互不影响地执行。当函数中用到全局变量时,其作用可分为三类:仅用于输入数据、仅用于输出数据、既用于输入数据又用于输出数据。全局变量用于输入数据时,通常会破坏函数的封闭性。由例7-14可知实际上没有必要让其用于输入数据,因此尽量避免这种用法。当全局变量用于输出数据时,既不会破坏函数的封闭性,又可以使函数返回多个函数值,但是这种用法会降低函数的可重用性和可读性。)
3. 通过例7-12体会文件作用域的进一步扩展并比较其与文件包含方式的区别。
4. 全局变量作用域为何可以扩展?(全局变量与局部变量的区别在于拥有相关存储单元的时间。用static关键字修饰的变量应该为全局变量而不应该被称为“局部变量”。如果认为其是局部变量,则为何其可以保持状态难以解释。如果认为其是全局变量,则为何其不能在其它地方使用?因为static关键字的作用就是限制文件作用域的范围的。)
5. 在函数中如何合理地使用全局变量?如何理解static关键字的作用?
6. 分析例7-16中的randomize函数为何可以产生随机序列。
(四)函数嵌套调用与一维数组作为函数参数
重点:
1. 理解嵌套调用函数时程序的执行过程。
2. 一维数组作为参数时的特别之处。(通过形参可以改变其元素的值。长度被忽略因此可以省略不写,但通常用一个整型形参专门用于传递数组的长度。)
难点:
分析对比例7-17和例7-20,体会函数的重用。
(五)递归
再次强调:递归函数是个奇迹,优雅地模拟了递归算法。
重点:
1. 理解递归算法。
2. 理解递归函数的执行过程本质上是函数嵌套调用的执行过程。
难点:
1. 用递归算法解决实际问题。
2. 从算法的角度分析递归函数的执行过程。
注意:
程序实际上模拟了我们解决问题的步骤,递归函数也不例外。建议通过看视频来学习递归这一节。
(六)库函数简介
熟悉常用的库函数,通过使用库函数来提高编程效率。
重点:
1. 理解getch函数、getche函数和getchar函数的区别与联系。
2. 分析在程序运行时如何得到与上次运行程序不同的随机序列。
3. 常见字符串处理函数的功能及注意事项。(相关字符数组必须能容纳新的字符串。)
(七)综合实例:确定y年m月d日是星期几。
重点:
1. 体会自顶向下分析方法与函数的结合。
2. 体会使用函数组织程序的优点。(1.便于多人同时开发程序,效率高。2.程序可读性好。3.可方便重用以函数包装的代码。)