阅读 ‧ 电子书库 实际参数和形式参量
实际参数是函数调用时出现在圓括号中的表达式。而形式参量则是函数定义中在函数头部声明的变量。当一个函数被调用时,将创建被声明为形式参量的变量,然后用计算后得到的实际参数的值初始化该变量。在程序清单9.2中,‘*’,和WIDTH是第一次调用show_n_char()时的实际参数,而SPACE和11则是第二次调用该函数时的实际参数。在函数定义部分,ch和num是函数的形式参量。
9.1.7 黑盒子观点

现在我们以黑盒子的观点来考察函数show_n_char()。输入是要显示的字符和显示次数,而执行结果是打印出指定数目的字符。输入以参数的形式传递给函数。这些信息清楚地表明了在main()中调用这个函数的方法。同时,这也可以作为编写该函数的设计说明。

黑盒子方法的核心部分在于ch、num和count都是show_n_char()私有的局部变量。也就是说,如果在main()中使用相同名字的变量,它们相互独立,互不影响。例如,如果main()中存在一个count变量,那么该变量值的改变不会影响show_n_char()中的count变量,其余变量也是如此。黑盒子内的一切操作对调用函数来说是不可见的。

9.1.8 使用return从函数中返回一个值

前面讨论了从调用函数到被调函数的通信方法。需要沿相反方向传递信息时,可以使用函数返回值。为了进一步说明,我们将构建一个比较两个参数大小并将较小数值返回的函数。因为比较的是int类型的数值,所以函数被命名为imin()。同时,为了检查imin()的执行结果,需要编写一个简单的main()函数。这种用来测试函数的程序有时被称作驱动程序(driver)。驱动程序实际调用了被测试的函数。如果该函数成功地通过了测试,那么它就可以在一个更为重要的程序中使用。程序清单9.3中是驱动程序和最小值函数。

程序清单9.3 lesser.c程序

阅读 ‧ 电子书库

阅读 ‧ 电子书库

下面是一个运行示例:

阅读 ‧ 电子书库

关键字return指明了其后的表达式的数值即是该函数的返回值。在本例中,函数返回变量min的数值。因为min的类型是int,所以函数imin()的类型也是int。

变量min是imin()私有的,但是return语句把min的数值返回给了调用函数。下面这个语句的作用相当于把min的值赋给lesser:

阅读 ‧ 电子书库

能否用下面这个语句代替上句?

阅读 ‧ 电子书库

答案是否定的,因为调用函数并不知道min变量的存在。imin()中的变量是该函数的局部变量。函数调用imin(evill, evil2)只是复制了两个变量的数值。

返回值不仅可以被赋给一个变量,也可以被用作表达式的一部分。例如,可以使用下列语句:

阅读 ‧ 电子书库

返回值可以由任何表达式计算得出,而不是仅仅来自于变量。例如,可以使用以下代码来简化示例程序:

阅读 ‧ 电子书库

条件表达式的值是n和m中的较小者,并且该数值被返回给调用函数。尽管这里并不要求使用圆括号,但如果您想让程序更清晰或风格更好,可以把返回值放在圆括号内。

当函数返回值的类型和声明的类型不相同时会有什么结果呢?

阅读 ‧ 电子书库

这时,实际返回值是当把指定要返回的值赋给一个具有所声明的返回类型的变量时得到的数值。因此在本例中,执行结果相当于把z的数值赋给一个int类型的变量,然后返回该数值。例如,考虑以下的函数调用语句:

阅读 ‧ 电子书库

这将把数值1.5625赋给变量z。然而,return语句返回的则是int类型的数值1。

return语句的另一作用是终止执行函数,并把控制返回给调用函数的下一个语句。即使return语句不是函数的最后一个语句,其执行结果也是如此。因此,可以用下面的方式编写imin()函数:

阅读 ‧ 电子书库

许多(但不是全部)C程序员更倾向于只在函数结尾使用一次return语句,因为这样做更有利于阅读程序的人明白函数的执行流程。但是,在像以上这种小函数中多次使用return语句并没有大错。不管怎样,对用户来说,以上3个版本的函数是相同的,因为输入和输出完全相同。不同的只是内部的程序语句。下面的程序也具有同样的执行结果:

阅读 ‧ 电子书库

return语句使printf()语句永远不会执行。如果Fleppard教授在自己的程序中只使用该函数编译后的版本,那么他永远不会知道编这个函数的学生对他的真正看法。

您也可以使用以下语句:

阅读 ‧ 电子书库

这个语句会终止执行函数并把控制返回给调用函数。因为return后没有任何表达式,所以没有返回值,这种形式只能用于void类型的函数之中。

9.1.9 函数类型

函数应该进行类型声明。同时其类型应和返回值类型相同。而无返回值的函数应该被声明为void类型。在早期版本的C语言中,如果函数没有进行类型声明,则该函数具有默认的函数类型int。使用这种默认类型的原因是早期大多数C语言函数都是int类型的。但是,C99标准不再支持函数的int类型的默认设置。

类型声明是函数定义的一部分。但需要注意的是该类型指的是返回值类型,而不是函数参数类型。例如,以下的函数头表示函数使用两个int型的参数而返回值类型是double。

阅读 ‧ 电子书库

为正确使用函数,程序在首次调用函数之前需要知道该函数的类型。途径之一是在第一次调用之前进行完整的函数定义。但是,这种方式会使得程序难于阅读。而且,需要的函数可能在C库中或其他文件中。因此,通常的做法是预先对函数进行声明,以便将函数的信息通知给编译器。例如,程序清单9.3中main()函数包含以下几行:

阅读 ‧ 电子书库

第二行代码说明imin是一个函数名称并且该函数返回一个int类型的数值。这样当在程序中调用函数imin()时,编译器就会有相应的处理方法。

在上面的代码中函数的预先声明被放在了调用函数之外。也可以在调用函数内部预先声明被调函数。例如,程序lesser.c的开始部分也可以写成如下形式:

阅读 ‧ 电子书库

在以上两种形式中,需要重点注意的是函数声明要在使用函数之前进行。

在ANSI C标准库中,函数被分成几个系列,每一系列都有各自的头文件。这些头文件包含了本系列函数的声明部分。例如,头文件stdio.h包含了标准I/O库函数的声明,像printf()、scanf()。而头文件math.h是对各种数学函数进行声明。例如它使用以下代码通知编译器函数sqrt()返回double类型的数值:

阅读 ‧ 电子书库

但是不要把函数声明和函数定义混淆。函数声明只是将函数类型告诉编译器,而函数定义部分则是函数的实际实现代码。引用math.h头文件只向编译器说明了sqrt()的返回值类型double,但是sqrt()的实现代码则位于另外一个库函数文件中。