1
C语言程序设计
1.7 第6章 函  数

第6章 函  数

一、模块化程序设计方法

在学习C语言的函数以前,我们需要了解什么是模块化程序设计方法。人们在求解一个复杂问题时,通常采用的是逐步分解、分而治之的方法,也就是把一个大问题分解成若干个比较容易求解的小问题,然后分别求解。程序员在设计一个复杂的应用程序时,往往也是把整个程序划分为若干功能较为单一的程序模块,然后分别予以实现,最后再把所有的程序模块像搭积木一样装配起来,这种策略被称为模块化程序设计方法。

在C语言中,函数是程序的基本组成单位,因此可以很方便地用函数作为程序模块来实现C语言程序。利用函数,不仅可以实现程序的模块化,使程序设计简单和直观,提高程序的易读性和可维护性,而且还可以把程序中常用的一些计算或操作编成通用的函数,以供随时调用,大大减轻程序员的代码实现工作量。

函数是C语言的基本构件,是所有程序活动的舞台,虽然在前面各章的程序中都只有一个主函数main(),但实用程序往往由多个函数组成,可以说C程序的全部工作都是由各式各样的函数完成的,所以也把C语言称为函数式语言,其通过对函数模块的调用实现特定的功能。C语言中的函数相当于其他高级语言的子程序。C语言不仅提供了极为丰富的库函数(如Turbo C和MS C 都提供了三百多个库函数),还允许用户建立自己定义的函数。用户可把自己的算法编成一个个相对独立的函数模块,然后用调用的方法来使用函数。

由于采用了函数模块式的结构,C语言易于实现结构化程序设计,使程序的层次结构清晰,便于程序的编写、阅读、调试。在编写较大的程序时,应该特别注意程序的功能分解,在这里也就是函数分解。也就是说,应该把程序写成一组较小的函数,通过这些函数的互相调用完成所需要的工作。初学者往往不注意函数分解,写出的程序经常是一大片,没有结构性。实际上,在学习程序设计的过程中强调函数分解是绝对必要的,没有合理的函数分解,完成规模较大的程序将更困难,要花费更多时间,写出的程序通常也更难理解,出现了错误更难发现和改正。这一点值得读者特别注意。

问题是:什么样的程序片段应当定义成函数呢?这并没有万能的准则,程序设计者需要自己分析问题,总结经验。这里提出两条线索,供读者学习时参考:

1.程序中可能有重复出现的相同或相似的计算片段。可以考虑从中抽取出共同的东西,定义为函数。这将使一项工作只定义一次,需要时可以多次使用。这样做不但可以缩短程序,也将提高程序的可读性和易修改性。

2.程序中具有逻辑独立性的片段。即使这种片段只出现一次,也可以考虑把它们定义为独立的函数,在原来需要这段程序的地方写函数调用。这种做法的主要作用是分解程序的复杂性,使之更容易理解和把握。

把程序分解为相应的功能模块,设计好它们之间的信息联系方式后,就可以用独立的函数分别实现了。显然,与整个程序相比,各部分的复杂性都更低了。

很难说什么是一个程序的最佳分解。对一个程序可能有许多种可行分解方式,寻找比较合理或有效的分解方式是需要不断学习和实践的。熟悉程序设计的人们提出的经验准则是:如果一段计算或工作可以定义为函数,那么就应该将它定义为函数。

二、函数的分类

在C语言中可从不同的角度对函数分类。

1.从函数定义的角度看,函数可分为库函数和用户定义函数两种。

(1)库函数

由C系统提供,用户无需定义,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。在前面各章的例题中反复用到printf 、scanf 、getchar、putchar、gets、puts、strcat等函数均属此类。

(2)用户定义函数

由用户按需要写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。

2.从功能角度看,又可把函数分为有返回值函数和无返回值函数两种。

(1)有返回值函数

此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值,如数学函数即属于此类函数。由用户定义的这种要返回函数值的函数,必须在函数原型说明和函数定义中明确返回值的类型。

(2)无返回值函数

此类函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。由于函数无需返回值,用户在定义此类函数时可指定它的返回为“空类型”,空类型的说明符为“void”。

3.从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。

(1)无参函数

函数定义、函数原型说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。此类函数通常用来完成一组指定的功能,可以返回或不返回函数值。

(2)有参函数

也称为带参函数。在函数定义及函数原型说明时都有参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,称为实际参数(简称为实参)。进行函数调用时,主调函数将把实参的值传送给形参,供被调函数使用。

以上各类函数不仅数量多,而且有的还需要掌握一定硬件知识才会使用,因此要想全部掌握则需要一个较长的学习过程。我们应首先掌握一些最基本、最常用的函数,再逐步深入。由于篇幅关系,本书只介绍了很少一部分库函数,其余部分读者可根据需要查阅有关手册。

还应该指出的是,在C语言中,所有的函数定义,包括主函数main在内,都是平行的。也就是说,在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。但是函数之间允许相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数还可以自己调用自己,称为递归调用。main 函数是主函数,它可以调用其他函数,但不允许被其他函数调用。因此,C程序的执行总是从main函数开始,完成对其他函数的调用后再返回到main函数,最后由main函数结束整个程序。一个C源程序必须有,也只能有一个主函数main。

三、主函数

每个C程序里总有一个名为main的特殊函数,常称为主函数。主函数规定了整个程序执行的起点,专业术语是程序入口。程序执行从这个函数开始,一旦它执行结束,整个程序就完成了。程序里不能调用主函数,它将在程序开始执行时被自动调用。

除了主函数外,程序里的其他函数只有在被调用时才能进入执行状态。所以,一个函数要在程序执行过程中起作用,要么它是被主函数直接调用的,要么是被另外一个被调用正在执行的函数所调用的。没有被调用的函数在程序执行中不会起任何作用。