
7.2.2 函数调用的方式
按照函数调用在程序中出现的位置,把函数调用方式分为三类。
(1)把函数调用作为一条语句。看如下代码:

(2)函数调用出现在一个表达式中,这种表达式称为函数表达式,此时要求函数带回一个确定的值以参与表达式的运算。看如下代码:

(3)函数调用甚至可以作为另一个函数调用的参数。看如下代码:

上面这行代码比较有趣,调用了两次whichmax函数,但显然,系统肯定是先计算实参的值,也就是先调用whichmax(12,19)函数计算出值来,然后才能调用外面这个whichmax函数,而不能先计算外面的whichmax函数,因为其实参值还没确定下来。
7.1节调用函数时遇到了一个编译错误,这个错误产生的原因其实是因为违反了“调用一个函数之前应该先声明该函数”的原则。回顾一下当时的代码,当时在main函数中调用了printhello函数,但是如果printhello函数写在main函数下面,就会编译出错,怎么办呢?当时的解决方法是把printhello函数直接写到main函数上面,这也叫把printhello函数定义在了main函数上面,这种把printhello函数定义在main函数上面的写法,就等价于该函数声明了自己,所以main函数中可以调用printhello函数。但是,如果函数太多,A函数要调用B函数,必须把B函数写在A函数上面,C函数要调用D函数,必须把D函数写在C函数上面,就好像必须把printhello函数写在main函数上面一样,一会就晕了,不知道究竟哪个函数该写在哪个函数上面。
所以,需要通过函数声明来解决这个问题,只要声明过的函数,都可以被调用而不管该函数定义在什么位置(甚至写在不同的文件中也没问题),如此说来,应该意识到,必须把函数声明放在任何源代码文件的具体函数调用代码之前(例如写在源代码文件的开头),才能保证调用函数时这些被调用的函数已被声明。
函数声明的一般形式为:

观察一下,这个函数声明的一般形式和函数定义的一般形式以及和函数调用的一般形式相比,有什么区别。看看如下范例:
(1)如下是函数定义。

(2)如下是函数声明。

(3)如下是函数调用。

再看一例:
(1)如下是函数定义。

(2)如下是函数声明。

(3)如下是函数调用。

可以看到,只要把函数定义的第一行拿过来,末尾加个分号,然后把整个函数体({}包着的部分)去掉,得到的这一行,就是函数声明。
为了通用性和使用方便,可以把所有自定义的函数(当然不包括main函数)的函数声明写在一个.h头文件中,然后在每个源代码文件的开头部分,用#include语句把这个.h头文件包含进来,这就相当于声明了所有的自定义函数,后续就可以在源代码中随意调用这些函数了。
要严格区分函数定义和函数声明的区别:函数定义里面包含函数体,函数体中的代码确定了函数要执行的功能。而函数声明,只是对已定义的函数进行说明,不包含函数体,函数声明可以提前指明该函数的参数类型、返回值类型等,让该函数的调用者明确知道这些信息,这样该函数的调用者就能够辅助编译器检查调用该函数时有没有参数类型错误、返回值类型错误等各种错误的存在。