C语言非常道
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6.2 函数调用和函数调用运算符

在这个程序里,除了main函数,还有一个叫作cusum的函数。我们说过,函数可以从它的调用者那里接收数据以供内部使用,但是,要想接收这些数据,而且能够在函数内部使用,必须依赖于变量。为此,就要在函数名后面的圆括号内声明这些变量以接受调用者传来的数据。作为函数声明的一部分,这些在圆括号内声明的变量称为参数。在这里,所谓的参数就是r,其类型为unsigned long long int,简称参数r。

习惯上,我们把参数r叫作形式参数,简称形参。本质上,参数是从外部传递到函数内部的数值,变量r只是承载这个数值的中转容器,是形式上的参数,而不是实际的参数,传递的内容(值)才是实际的参数,这就是“形参”这个名称的由来。

函数是可以反复执行的,每调用一次,它就执行一次。每当函数开始它的一次执行时,就会创建圆括号内声明的参数变量;而当函数返回后,这些变量被销毁。所以,每当cusum函数开始执行时,就会创建一个变量以接受调用者传递的值,这个变量由标识符r指示和代表着,可称之为变量r,或者参数变量r。

所谓的“销毁”只是一种形象的说法,变量是一个存储区,没有谁能够毁掉它,它一直就在那里,在存储器或者处理器中。因此,所谓的“销毁”仅仅是指你不能再合法地使用它了,这个存储区域恢复了自由之身,或者又分配给别的用途了。

函数是一个可反复使用的代码块,对它的使用是通过所谓的函数调用进行的,如果函数的返回类型不是void,则每次调用后还将返回一个数值。

来看main函数,我们先是声明了三个unsigned long long int类型的变量x、y和z。然后,语句

              x = cusum(10);

的意思是调用函数cusum并将数字10传递给函数的参数r,然后,等函数返回后,将返回值保存到变量x。

当然,这只是大体的说法,对于这条语句我们还必须做更细致的分析。首先,该语句是一个表达式语句,由表达式x = cusum(10)和一个分号“;”组成。在这个表达式里有一个赋值运算符和一对圆括号,赋值运算符我们认识,但也别把土豆不当干粮,这一对圆括号也是运算符,称为函数调用运算符。

函数调用运算符的优先级高于赋值运算符,所以,这里的cusum是函数调用运算符的操作数,而赋值运算符的操作数是左值x和表达式cusum(10)的值。

在函数的声明里,标识符cusum的身份是函数的名字,而当它出现在一个表达式应该出现的位置时,它的身份是表达式,用于指示或者说代表一个函数。在C语言里,指示或者代表函数的表达式叫作函数指示符。

显然,如果一个函数指示符的后面是一对圆括号,那它们就合在一起形成一个更大的表达式,称为函数调用表达式。函数指示符是函数调用运算符的左操作数,其他操作数位于圆括号内部,它们是传递给函数的实际参数。

在C语言里,每个表达式都有值。表达式2 + 3的值是5,而对于函数调用表达式来说,它的值是函数调用的返回值,这也是函数调用运算符的结果。如果函数的返回类型是void,则函数返回空值,且函数调用表达式的值也是空值。

对于初学者来说,他们关注的重点往往在函数调用本身,而忽略了函数调用表达式还会有值。对于表达式x = cusum(10)来说,你应该忘记子表达式cusum(10)会发起函数调用的这个事实,而把它看成一个黑盒子,这个黑盒子最终会化为一个值,并被保存到变量x中。

在main函数内的第一条语句里,函数调用表达式cusum(10)引发函数的第一次执行。当函数cusum开始执行时,创建参数变量r并将它的存储值修改为调用者传递的参数值10,然后,变量r就可以在函数内部使用了。

我们说过,参数是从外部传递到函数内部的数值,这个数值是由函数的调用者通过函数调用表达式提供的,这才是实际上的参数。习惯上,我们把由调用者给出的实际上的参数称为实际参数,简称实参。

后面两条语句

              y = cusum(100);
              z = cusum(1000);

执行动作与第一条语句没有本质区别,唯一的区别是传递的实参不同,函数的返回值也不同,读者可以通过调试器GDB观察变量x、y和z的值。