函数调用
第九章:函数调用
概述
前面的一章讲解了函数的基础,包括函数的概念,函数的定义和函数的组成
一个函数再被定义之后只有在被调用时才会实现它的功能,因此一个不被调用的函数是没有意义的.
函数调用指的是一个函数(主调用函数)暂时中断本函数的运行,转而执行另一个函数的过程
被调用函数执行完成之后,返回到调用函数的中断处继续执行调用函数,即返回主调用函数
函数的一个调用必定伴随着一个返回过程
而在这个返回过程中发生信息的交换
本章内容如下:
-
被调用函数的声明与函数原型
-
函数调用的一般形式
-
函数调用的形式
-
函数嵌套和递归调用
-
变量作用域
被调用函数的声明与函数原型
函数的声明
一个函数想要被另一个函数调用之前,分别需要具备下面这个先决条件:
- 函数必须是已经存在的函数.被调用函数可以是库函数,也可以是用户自定义的函数
关于什么是库函数将在后面的章节讲解根据
根据函数具体类型的划分,到底是库函数还是用户自定义的函数,具体的函数调用的声明如下:
-
如果要调用库函数,就需要在程序开头导入库函数,将库函数导入到程序中
例如:
//我们平时用的printf函数和scanf函数其实是C语言自带的库函数.导入命令如下: #include <stdio.h> //stdio.h其实就是printf和scanf这两个库函数的位置 //通过include这样一个命令就告诉编译器在编译我这个程序的时候将库函数拿来一起编译 //如果是需要用其他函数则导入对应的文件就行了,例如math.h //也就是说库函数其实是前人已经写好的程序段,我们导入之后直接用 //关于库函数具体在什么时候调入,将在后面的章节讲解
-
如果调用用户自己定义的函数,根据用户自己定义的函数的位置,又能分成两种:
-
用户定义的函数在主调用函数之前:直接调用即可
例如:
//sum函数功能是计算两个数的和 int sum(int a, int b){ int sumOfab; sumOfab=a+b; return sumOfab; } void main(){ sum(2,3); }
-
用户定义的函数在主调用函数之后:需要先在主调函数中对函数类型,函数名和形式参数进行声明
声明的作用就是告知编译器这里有用户自定义的函数,先跳过主程序的编译,去编译在后面的函数(编译按顺序从上到下)
声明的一般格式为:返回值类型 函数名(参数类型声明表)
-
参数类型声明表为
参数类型 参数名,参数类型 参数名.....
例如:
void main(){ //变量命名 int sumOfab(int a,int b); sumOfab(2,3); } int sumOfab(int a, int b){ int z; z=a+b; return z; }
-
-
需要注意的是:
- 声明和定义不同.
定义是指对函数功能的确定,包括确定函数类型,函数名,参数及类型,函数体等
声明则是指通过特定的语句通知编译器以便编译器在遇到函数的时候能够正确识别函数.
函数原型
函数原型就是指包括函数类型,函数名,参数类型声明表在一起的一个整体
例如:
int funct(int a, int b);
函数原型的返回值类型和参数个数及对应类型应该和定义的函数一致.
而且实际参数需要能够被形式参数类型所兼容
函数原型的出现就是为了减少程序的bug,使得编译器能够得知自定义的函数的参数类型进而能够检查自定义的函数是否正确.
函数调用的一般形式
函数调用的一般形式为:
函数名(实际参数列表);
需要注意的点如下:
-
如果调用无参函数,则实际参数列表可以没有,但是括号不能省略
-
如果有多的实际参数,则各个参数之间用逗号隔开
-
实际参数的个数应该与形式参数的个数相等且类型匹配
-
系统实际参数列表赋值顺序不一样,有的系统从左向右依次赋值,有的系统从右向左依次赋值
例如:
void main(){ float funct(float x, float y); float a,b,c; a=6.0; b=3.0; c=funct(a,b); printf("%f",c); } float funct(float x,float y){ int z; z=x/y; return z; } >>>2.00000
如果从左到右给参数赋值,那么结果就是2,如果从右到左给参数赋值,那么结果就是0.5
函数调用的形式
上面讲解的是函数调用的一般形式
但是具体根据函数在主调函数中的位置,可以细分为以下三种调用方式
作为单独语句
将函数作为一个单独的语句来调用.
例如:
printf("666");
作为表达式
函数出现在一个表达式中,这种表达式也称为函数表达式
这样的函数通常具有返回值可以参与运算
例如:
m=square(a);
n=3+square(a);
作为参数
函数可以作为一个函数的实际参数出现
和作为表达式函数一样,作为参数的函数通常具有返回值.
例如:
c=sum(a,sum(b,c));
需要注意的是:
- 正式用于函数可以作为函数调用,因此就有函数的嵌套和递归调用
函数的嵌套和递归调用
C语言中的函数之间是相互平行的,它们的地位相等.因此函数不允许嵌套定义
但是C语言中的函数允许嵌套和递归调用,下面就将讲解C语言中函数的嵌套和递归调用
函数的嵌套调用
函数的嵌套调用指在一个函数的内部调用了其他函数
其实主函数调用其他函数的时候就是在进行函数的嵌套调用
函数的递归调用
函数的递归调用是指函数运行过程中直接或者间接的调用了函数本身
函数可以递归调用是C语言的一个重要特性,它使得C语言在处理一些递归问题中特别的方便.
但是需要注意,如果递归调用不得当会造成无限循环
例如:求斐波那契数列就可以用循环调用
int Fibo(int n){
if((x==1)||(x==2)){
return 1;
}
else{
return Fibo(x-1)+Fibo(x-2);
}
}
void main(){
int i; //定义循环指针
for(i=1;i<=20;i++){
printf("%d\t",Fibo(i));
if(i%5==0){
printf("\n");
}
}
}
变量的作用域
变量的作用域是指变量能够起作用的范围.
如果一个变量在某个函数内起作用,那么这个变量的作用域就是该函数
根据变量作用域的大小,我们将变量分为全局变量和局部变量
但是由于变量的存储类别,因此对于变量具有更多的操作,这点将放在后面讲解
全局变量
全局变量是指在函数外定义的变量.
全局变量可以为本C程序中的所有函数使用.
无论通过函数的数值传递还是通过指针操作
需要注意的是:
- 全局变量增强了函数间的依赖性,最好不要多用
- 全局变量的过多使用会降低函数的清晰性.
局部变量
局部变量是指在一个函数内定义的变量
我们前面讲过调用函数的时候,系统会暂时中断主程序的运行转而运行调用的函数,并且为调用的函数开辟一个内存空间来供其使用.