一.函数的定义
函数由函数名,参数和函数体组成。参数用来接收调用函数传递给它的数据;函数体则是函数实现自身功能的一组语句。函数定义的一般形势:
类型说明符 函数名(形式参数声明)
{
}
1)类型说明符用来说明函数返回值的类型;
2)函数名是用户自定义的用于标识函数的名称
3)形式参数声明(简称形参表)用于指明调用函数和被调用函数之间的数据传递;传递给函数的参数可以有多个,也可以没有。当函数有多个参数时,必须在形参表中对每一个参数进行类型说明,每个形参之间用逗号隔开。形参的主要作用是接收来自函数外部的数据。一般情况下,函数执行需要多少原始数据,函数的形参表中就有多少个形参,每个形参存放一个数据。若函数没有参数,则形参表为空,但此时函数名后的括号不能省略。
例如 double sum(float a,float b, float c)
void prtinfo()
说明:函数不可以嵌套定义,即在函数中定义函数
eg:定义函数求三个数的最小值
int min(int x,int y ,int z)
{
int t;
if(x<y) t=x;
else t=y;
if(z<t) t=z;
return t;
}
二.函数的调用
函数的调用指的是一个函数(调用函数)暂时中断本函数的运行转去执行另一个函数(被调用函数)的过程。被调用函数执行完相应的功能后,返回到调用函数中断处继续调用函数的执行,这是一个返回过程。函数的一次调用必定伴随着一个返回过程。在调用和返回的过程中,两个函数之间通常发生信息交换。
函数的调用有两种方式:函数语句调用方式和函数表达式调用方式
1.函数语句调用方式
一般形式 函数名(【实际参数列表】)
函数语句调用方式适用于调用没有返回值的函数。这种函数通常仅是完成一些特殊的工作,函数定义是void类型的函数。
eg:
void print
{
printf(“input data!\n”)
}
int main
{
''''''
print() //函数调用过程,没有返回值,相当于一串语句的缩写
''''''
return 0;
}
2. 函数表达式调用方式
一般形式 函数名(【实际参数列表】)
这种调用方式是以表达式的形式调用函数,用于调用有返回值定义的函数,通过调用函数的表达式接收被调用函数送回的返回值。函数调用出现在一个赋值表达式中,要求函数带回一个确定的值参与表达式的运算。
eg int max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
int main()
{
int a,b,x,max;
scanf("%d%d",&a,&b);
Max=max(a,b); //函数调用过程,调回确定的值a或b参与赋值运算
printf("Max=%d",Max);
return 0;
}
说明: 1
1)函数调用中实际参数列表(简称实参表)里实参的类型与形参的类型相对应,必须符合赋值兼容的规则,实参个数必须与形参相同,并且顺序一致,当有多个实参时,参数之间用逗号开
2)实参可以是常量、有确定值的变量或表达式及函数调用。当进行函数调用时,系统计算出实参的值,然后按照顺序传给相应的形参。例如:
to_stu(120);
to_stu(20+a+b);
cube(cube(x+y));
3)尽量不用b=sum(a,a+=4);这种可能引起歧义的语句,建议使用
x=a+4;b=sum(a,x);
三.函数返回
函数的返回值或执行结果是通过return语句带回到调用函数的
1.返回语句
return(expression);
return expression ;
return ;//return语句无表达式,此时它的作用仅仅是使程序执行的流程返回到调用函数的调用位置继续执行调用函数
功能:使程序控制从被返回语句返回调用函数,并带回返值。
说明:
1)void型函数无返回值,无return语句时,遇}自动返回;
“需要注意的是,若函数中无return语句,函数也并非没有返回值,而是返回一个不确定的值。为了明确表示函数没有返回值,需要用void将函数定义为‘空类型’;若连形参也没有,形参表可为空。
返回值为void类型的函数,尽管也是遇到return语句返回,但不要求必须有return语句。由于没有返回值,故其不能作为表达式的一部分,通常都是单独调用以完成某项功能”
2)函数中可有多个return语句,但是return只能返回一个值(通常与if语句多次配合使用)
换句话说,执行到哪个return语句,哪个起作用。
3)若函数类型与return语句中表达式的值类型不一致,按前者为准,自动转换
eg : int Max(float a,float b)
{
float c;
c=a>b?a:b;
return c;
}
int main()
{
float x,y;
scanf(“%f%f”,&x,&y);
printf(“max=%d\n”,Max(x,y));
return 0;
}
输入 6.2 3.7 <回车>
运行结果
max=6
四.函数参数传递方式
函数定义中的参数称为形参,函数调用时的参数称为实参,两者必须在数据类型、顺序和数量上一一对应。在C语言进行函数调用时,有两种不同的参数传递方式,即值传递和地址传递。
1.值传递
在函数调用过程中,实参将其值传递给形参,这种传递方式即值传递。
“C语言规定,实参对形参的数据传递是单向‘值传递’,即只能由实参传递给形参。这是因为,在不同的程序模块中变量属于不同的程序存储空间,,,,,调用函数时,系统会对形参分配存储单元,并将实参对应的值传递给形参,调用结束后形参单元被释放,实参单元仍维持原值。因此,在执行一个被调用函数时,形参的值如果发生变化,并不会改变调用函数中实参的值。”
eg : void add(int a,int b)
{
a+=3;
b+=6;
printf(“a=%d,b=%d”,a,b);
}
int main()
{
int x=1,y=2;
add(x,y);
printf("x=%d,y=%d",x,y);
return 0;
}
运行结果:
a=4,b=8
x=1,y=2
2.地址传递,详见指针。
五.函数的原型声明
如果自定义的函数放在调用函数的后方,就需要对函数进行原型声明,格式为:
类型说明符 函数名 (参数表);
说明:
1) 形参表中可只给出形参类型,忽略形参名字:
eg : float fun(float,float,int)
2) 如果在所有函数定义之前,在源程序文件开头,即在函数的外部已经对函数进行了声明,则在各个函数中不必再对所调用的函数进行声明。例如:
#include<stdio.h>
float f1(float,int);
float f2(int,int);
3) 当被调用的函数与调用函数不在一个文件中时,必须使用函数声明,以保证程序编译时能够找到该函数。通常将多文件编译时的函数声明放在自定义的.h文件中,然后在调用函数头部包含该.h文件。
六.数组作为参数
“单个数组元素可以作为函数参数,其使用和定义与简单变量作为参数完全一样,即遵守‘值传递’的方式。
同样,数组名也可以作为函数参数。用数组名作为参数时,实参采用数组名,实参像形参传递的是数组的首地址,数组元素本身不被复制,采用的是地址传递的方式。”
1.一维数组作为函数参数
形参的写法:类型说明符 形参数组名【数组长度】
eg: float average(float array【20】)
为了提高函数的通用性,一维数组形参说明时可以不指定数组长度,但是方括号不能省略
“需要注意的是,数组作为实参时仅需要给出数组名,而不能加长度说明,因为实参数组已经被定义,而且被输入了具体的值,这里只是将实参数组的首地址值传给形参数组。”
所以这个调用语句aver(a【10】)是错误的。
2.二维数组作为函数参数
形参的写法:
类型说明符 形参数组名【数组长度1】【数组长度2】
例如: int srh_min(int array【3】【4】)
“二维数组作为函数参数时,可以不指定第一维长度,但是第二维长度不能省略,因为系统必须知道列数才能正确计算一个数组元素在数组中相对于第一个函数的偏移位置。”
七.函数的嵌套调用和递归调用
1.函数的嵌套调用
“C语言中函数的定义是相互平行的,函数之间没有从属关系,但是,一个函数在被调用的过程中可以调用其他函数,这就是函数的嵌套调用”
2.函数的递归调用
“所谓递归调用,就是在调用一个函数的过程中又直接或间接地调用函数本身。”