小结
概念与术语
■ 函数是构成C语言源程序的基本单位。C语言源程序由若干函数组成。
■ 如果是在操作系统下运行,那么相应的C语言源程序必须要有且只能有一个main()函数。
■ main()函数是程序执行的起点。
■ 函数是具有特定功能的一段代码模块。
■ 函数声明的作用主要是向编译器说明函数名这个标识符的意义,除了需要用类型说明符“()”来说明该标识符是个函数名之外,还需要描述这个函数需要几个什么样的参量以及求一个什么样的值。
■ 函数的声明也叫函数原型(Prototype)。
■ 函数原型有助于在编译时发现程序中在函数调用方面可能存在的错误。
■ 在调用函数处和写函数声明的地方不需要考虑实现函数功能的细节,这种思想方法有助于把握复杂的程序并提高软件的质量。
■ 声明不求值的函数要使用void关键字修饰函数名。
■ 声明一个不需要任何参量的函数,其参量类型列表部分应该写void。
■ 不用写关于main()函数的函数原型,因为main()函数的原型是由C语言规定的,而其他各个函数都是由程序编写者定义的。
■ 函数定义是指具体写出函数完成任务的步骤和方法。
■ 函数定义有两个部分:函数头和函数体。
■ 函数定义的位置必须在其他函数定义的外部。
■ 形参是为了描述函数执行的步骤而事先假设的函数所需要的参量的名字。
■ 形参的作用域在自己函数定义的范围之内。
■ 关键字return的功能有两个:将程序控制返回函数调用处;返回一个值。
■ 如果函数体内没有return语句,函数将在执行到函数体的“}”时返回调用处。
■ 函数返回值应该与函数类型一致。
■ 函数调用的本质是一种运算,函数调用是一个表达式。
■ 实参是函数执行时所需要的真正的参量的值。
■ 实参应该与形参在类型、个数及顺序上保持一致。
■ 实参是一个有值的表达式,函数调用时形参把对应实参表达式的值作为自己的初值。
■ C语言对实参的计算次序没有规定。
■ 函数调用表达式的类型就是函数返回值的类型。
■ 库函数是编译器提供的编译好的、以库文件形式存在的、可以直接使用的函数。
■ 使用库函数同样应该首先进行函数声明。
■ 库函数的函数原型写在若干扩展名为.h的文本文件中。
■ 库函数的声明可以通过编译预处理命令#include<对应的头文件>实现。
■ 局部变量是指在函数内(包括形参)定义的变量。
■ 局部变量只能在所在的代码模块中使用。
■ 如果两个变量的作用域重叠,编译器将按照“局部优先”的原则处理。
■ 在同一个作用域定义两个同名的变量是一个语法错误。
■ static类别的局部变量在程序运行期间一直存在。
■ static类别的局部变量的赋初值只进行一次。
■ static类别的局部变量的初始值是在程序运行开始(编译时)获得的。
■ 如果没有显式的赋初值,那么static类别的局部变量的初始值为“0”。
■ auto类别的局部变量是在程序执行到所在代码段时才存在的,离开相应的代码块时,auto类别的局部变量不再存在。
■ auto类别是局部变量的默认类别。
■ 应尽量避免使用外部变量。
■ 递归就是对自身的调用进行函数定义。
■ 程序中不允许有无穷递归。
■ 写递归函数有两个要点:递归的关系及递归的终止。
■ 递归的本质是以形参为“循环变量”对“函数调用”的“循环”。递归是一种分而治之解决问题的编程技术。
■ 程序的质量:没有语法错误;没有逻辑错误;程序具有良好的结构和程序设计风格,具有很好的可读性、可修改性、可移植性和可测试性。
风格与习惯
在写函数原型时,有一种风格喜欢在参数类型后面写上标识符。如:
在这里,chengshul、chengshu2没有任何语法意义,编译器会忽略这两个标识符。所以没有必要写。当然,如果你认为这会使代码的可读性更好的话,也可以采用这种风格写函数原型。
常见错误:
■ 函数原型后缺少“;”。
■ return的表达式的值与函数返回值的类型不一致,尽管在语法上有时这是允许的,但多数情况下会导致含糊和错误。
忠告
■ 不要写重复的代码,应该用函数实现。
■ 即使只调用一次,也应该尽量把独立的功能写成函数实现,这样会使代码干净、整洁、清晰,易于修改。
■ 所有的函数(包括main())都应该尽量简单、短小,小到你有足够的能力把握其正确性。
■ 在写函数定义之前先写函数原型,这样的思维方式会使编程有条理。
■ 把函数定义写在函数调用之前以代替函数原型会使源代码显得“头重脚轻”。
■ 首先写出空的函数定义,然后再快速地搭建出合乎语法要求的源程序框架,然后再逐步向其中添加内容。
牛角尖
■ main()函数可以递归调用吗?
当然可以。在C语言中各个函数的地位是平等的,main()函数除了是程序执行的起点且不必写函数原型之外(16)没有任何特殊的地方。
■ 对于一个有值的函数,如果没有写return语句会发生什么?
很难说会返回什么值。