二、函数调用方式和嵌套调用
1、函数调用的一般形式
上一节演示了函数调用的方法,如int result=add(3,4);就是对add函数的调用。
函数调用的一般形式为:
函数名(实参列表) ;
注意:若调用的是没有形参的函数,实参列表可以没有,但圆指号不能省略。如果实参列表包含多个参数,则各个参数之间用逗号分隔,而在函数定义中,如果函数的形参列表包含多个参数,也用逗号分隔。实参和形参个数要相等,类型耍 一致,按顺序对应,一一传递。
2、函数调用的方式
1)按照函数调用在程序中出现的位置 ,把函数调用方式分为三类。
(1)把函数调用作为一条语句。
例:
(2)函数调用出现在一个表达式中,这种表达式称为函数表达式,此时要求函数带回一个确定的值来参与表达式的运算。
例:
(3)函数调用甚至可以作为另一个函数调用的参数。
上面这行代码调用了两次 add函数,但显然,系统肯定是先计算实参的值,也就是先调用 add(3,4)函数计算出值来 ,然后才能调用外面这个 add函数。而不能先计算外面的 add 函数 ,因为实参值还没确定下来。
3)函数声明
上一节说过,函数要定义在main函数的上面,否则会报错。
问题:如果函数太多,A函数要词用B函数,必须把B函数写在A函数上面,C 函数要调用 D 函数 ,必须把 D 函数写在 C 函数上面,就好像必须把 printHello 函数写在 main 函数上面一样 ,一会就晕了,不知道究竟哪个函数该写在哪个函数上面。
解决方法:用函数声明的方式。只要声明过的函数,都可以被调用而不管这个函数定义在什么位置(甚至写在不同的文 件中也没问题)
函数声明的一般形式为:
返回类型? 函数名{形式参数列表);
函数声明的一般形式、函数定义的一般形式、函数调用的一般形式三者的区别:
(1)函数定义
(2)函数声明
把函数定义的第一行拿过来,末尾加个分号,然后把整个函数体{ }包着的部分去掉,就是函数声明。
(3)函数调用
为了通用性和使用方便,可以把所有自定义的函数(包括 main 函数)的函数,声明写在一个.h头文件中,然后在每个源代码文件的开头部分, 用 include 语句把这个.h 头文件包含进来,这就相当于声明了所有的自定义函数 ,后续就可以在源代码中随意调用这些函数了。
要严格区分函数定义和函数声明的区别,函数定义里面包含函数体,函数体中的代码确定了函数要执行的功能,而函数声明,只是对已定义的函数进行说明 ,不包含函数体 ,函数声明可以提前指明该函数的参数类型、返回值类型等,让该函数的调用者明确知道这些信息,这样函数的调用者就能够辅助编译者器检查调用这个函数时有没有参数类型错误、返回值类型错误等各种错误的存在。
4)函数的嵌套调用
对于函数定义来说 ,C 语言不允许在函数内部再定义另外一个函数 ,也就是说 C 语言中每个函数部是平行和独立的,这一点和某些编程语言不同,有些编程语言是允许在函数内部再定义其他函数的,这叫嵌套定义(一个函数定义里面套着另外一个函数定义),下面的代码在 C 语言中就是错误的:
虽然不能嵌套定义函数 ,但 C 语言允许嵌套调用函数,也就是说 ,在调用一个函数过程中,被调用的函数又去调用第三个函数,甚至第三个函数又去调用第四个函数......都是被允许的。
例:先定义三个独立函数nestingFun1,nestingFun2,nestingFun3
在源代码文件最前面,要对这三个函数进行函数声明。
在main中调用nestingFun1();结果显示如下:
下面修改nestingFun1函数,在函数中调用nestingFun2函数,如下:
执行结果:
下面修改nestingFun2函数,在函数中调用nestingFun3函数,如下:
执行结果:
这里的执行顺序如下:
main函数调用nestingFun1函数,
nestingFun1函数里执行nestingFun1开始语句
再执行nestingFun2函数
nestingFun2函数里执行nestingFun2开始语句
再执行nestingFun3函数
nestingFun3函数里执行nestingFun3开始和nestingFun3结束语句
nestingFun2函数里执行nestingFun2结束语句
nestingFun1函数里执行nestingFun1结束语句
这里讲解的函数嵌套调用 ,是为后面讲解函数递归调用打基础。