函数的调用
函数的定义一般在main函数外部。定义语句为:返回值类型 函数名(形参列表){代码区}
#include<stdio.h>
int func1(int a){//函数定义
//具体执行代码
return a;
}
int main(){
int a=0;
a=func1(a);//函数调用
}
函数的有效范围是从函数定义开始,到源代码末尾。如果将函数定义放在main函数后面,需要在main函数前添加函数声明以扩大函数的作用范围(新的范围为函数声明到源代码末尾)。如果将函数声明放在main函数中,则作用范围为函数声明到main函数末尾。函数声明方式为:返回值类型 函数名(形参列表);(注意此处的分号)。调用函数的方式:函数名(实参列表)。
在基本的函数调用时,我们无法在函数中使用main函数中定义的变量,而我们在函数中经常要引用main函数中的数据,所以就有了参数列表。我们通过它,将实参的值附给形参。从而使用main函数中的数据。不过,在自定义函数中形参的改变并不会对实参造成影响。这种传递方式也叫值传递。我们需要在函数定义时确定参数的个数和类型。多个函数参数之间用,隔开。注意,即使函数没有参数,函数定义和函数调用时的()也不能省。函数实参列表和形参列表要类型一致,一一对应。
函数形参调用之前并不分配内存,调用函数时分配内存。在函数调用之后,形参的内存将会被释放。因此,形参只能在函数内部使用。
自定义函数的返回值应与函数定义时标注的相匹配。函数的返回值为单,个变量。不能用函数返回数组。使用在函数中使用:return 返回值;来返回值。我们可以通过赋值语句来接收函数返回值。
在函数中我们可以调用其他函数,但C语言中,不允许函数定义中再包含函数定义。同时也不要企图调用main函数。
函数的调用方式及嵌套调用,递归调用
我们按函数调用出现的位置,可将函数调用分为三类:1.函数调用单独作为一条语句。2.函数调用出现在一个表达式中,这时,我们将这个表达式叫做函数表达式,这时,函数应有一个可以运算的返回值。3.函数调用作为函数参数。这是参数函数也应有一个类型确定的返回值。
函数嵌套调用就是在一个函数中使用另外的函数。当我们从一个函数进入另外的函数中时,原函数的内存并不会被系统释放,当里层函数调用结束后,先释放里层函数的内存空间,再返回原函数继续执行直到其调用完毕再释放其内存。打个比方,函数调用就像穿衣服一样,最先穿的只能最后脱,最后穿的只能最先脱。就像我们不可能穿100件衣服一样,多层函数嵌套也是极其占用空间的,因为多层的嵌套,中必然会包含很多的类型定义和形参变量,而在他们所在的函数空间释放前,它们和它们里层的函数内存空间都不会被释放。
函数的递归调用可以看成特殊的函数嵌套调用。代表的意思是函数自己调用自己。这样会产生一种问题,函数调用函数自己,被调用的自己再调用自己,这样就造成了一种死循环。因此,函数递归使用时一定要定义一个出口,以便在达到我们的需求后结束函数调用。出口一般由if语句和return组成。
以下是一段求阶乘的函数递归的范例:
#include<stdio.h>
int func(int a){
if(a==1)
return 1;//出口
else
return a*func(a-1);
}
int main(){
int a;
scanf("%d",&a);
a=func(a);//将a的阶乘赋值给a
}
当以上代码运行时,函数会一直递归,直到a为一,然后层层返回,直到返回所需要的阶乘。
函数递归的缺点是常常不能明确递归的层数,在函数递归达到一定的次数后,函数们所占的内存空间可能超出系统的规定,那么就会导致程序崩溃。
局部变量和全局变量
局部变量就是在一个函数内部定义的变量,它们仅在函数内部有效,只有在本函数内才能使用它们。也就是这个原因,main函数中定义的变量不能在我们定义的函数内使用,我们在自定义的函数中定义的变量也不能在main函数中使用。也因此,main函数和我们自定义的函数中定义的变量允许同名,而且毫不相干。总的来说,{}中定义的变量仅在本{}范围内有效。当{}内套{}时,它们中定义的变量不允许同名。
全局变量就是在函数外定义的变量,可以为本文件中其他函数所共用。全局变量的占用范围是从定义全局变量开始到本程序文件结束。全局变量在程序运行整个周期都占用内存。通过全局变量,我们加强了个个函数之间的联系,但也降低了函数的通用性,并降低了程序的可读性。如果某个函数想使用在它后面定义的全局变量,我们可以使用extern关键字来做一个外部变量声明,表示该变量在函数的外部定义。外部变量说明可以有多次,且不会重新给变量分配内存。具体使用形式为:extern 变量类型 变量名;。同时,在同一个原文件中,当全局变量和局部变量同名时,在局部变量的作用范围内,全局变量不再起作用,同时也不会受到局部变量的影响。
数组做函数参数
数组元素做函数参数
与普通变量一致。
数组名做函数参数
数组名也可以作为函数实参,数组名代表的是函数的的首地址,当数组名做函数实参时,向形参传递的就是数组的首地址。当我们用形参数组名来承接后,实参数组和形参数组所使用的就是同一段内存空间了,这时改变新参数值各元素的值就会对实参数组元素的值造成影响了。这种传递方式就不再是值传递了,而是叫地址传递。这和普通变量做函数参数就有了明显不同。在C语言中,形参数组的下标可以与实参数组的下标不一致或者不写(但类型必须一致),因为C语言编译器对形参数组不做检查,只是将实参数组的首地址传递给形参数组。当二维数组做函数形参时,可以省略一维大小,但不能省略二维大小。即使这样,但也应尽量保证形参和实参一致,以避免不必要的错误。