一、函数的定义
C语言的函数可分为库函数和用户定义函数两种。
(1)库函数。它是由编译器提供的,无须用户定义,它的源代码一般是不可见的。C程序中可以直接使用库函数,例如 printf、scanf、getchar、putchar、main函数。
(2)用户定义函数。它是由用户按照需求定义的函数,也是本单元重点介绍的内容。
C语言要求,变量必须先“先定义,后使用”,函数也遵循“先定义,后调用”的规则。函数定义时必须指定函数名、参数类型、要实现的功能等,这样编译系统在调用函数时会根据函数定义时所执行的功能来执行。函数定义的语法结构为:
返回值类型 函数名( 形式参数列表 )
{
函数体
}
(1)返回值类型:指定函数返回值的数据类型。如果函数没有返回值,则为void。
(2)函数名:指定函数的名称,是用户自定义的标识符。
(3)形式参数列表:参数是调用函数时传入的数据,函数定义时需要指定函数参数的名称和数据类型。函数可以有形式参数,也可以没有形式参数。依次函数分为有参函数和无参函数。
(4)函数体:用于实现该函数的功能,由C语言语句组成。
二、函数的调用
1.函数调用的形式
在程序中使用函数,就需要在main函数中调用它。C程序必须只有一个main函数。程序的运行从main函数开始,main函数调用其他函数。
(1)无参函数的调用
调用无参函数的语法结构: 函数名( );
#include <stdio.h>
//定义一个无参函数
void add(){
printf("这是一个无参、无返回值的函数");
}
int main(){
add(); //调用函数
return 0;
}
运行结果:这是一个无参、无返回值的函数
(2)有参函数的调用
与无参函数相比,有参函数在调用时,需要调用者传入参数值。调用有参函数的语法结构是:
函数名( 实参列表 );
#include <stdio.h>
//定义有参函数
void add(int x,int y){
int result;
result = x + y;
printf("%d+%d=%d",x,y,result);
}
int main(){
add(2,2); //调用函数
return 0;
}
运行结果:x+y=4
两个形式参数x和y。在调用此函数时,主调函数把实际参数的值传递给x和y。函数体中的语句用于实现两个整数的求和运算。
2.参数的传递方式
(1)形式参数和实际参数
在定义有参函数时,函数名后面括号中的参数称为“形式参数”,简称“形参”。在调用该有参函数时,函数名后面括号中参数称为“实际参数”,简称“实参”。
(2)参数的传递方式
参数的传递方式有两种:“值传递”和“地址传递”。“地址传递”方式中实参传递给形参的是地址,即实参和形参指向同一个内存空间。
在调用有参函数时,实参传递值给形参。需要说明以下两点。
(1)实参可以是常量、变量或表达式,但是必须有确定的值。
(2)实参与形参必须个数相等、顺序相等、类型匹配。实参和形参的数据类型必须相同或赋值兼容。
3.函数的返回值
通过函数调用可以使主调函数得到一个值,这个值就是函数的返回值。函数的返回值通过函数体中的return语句获得。如果函数没有返回值,那么函数定义时的返回值类型为void,函数体中不能使用return语句;如果函数需要有返回值,那么函数中必须使用return语句,而且返回值的类型与函数定义时的函数类型一致。
#include <stdio.h>
//定义有参函数
int add(int x,int y){
int result;
result = x + y;
return result;
}
int main(){
int sum;
sum=add(2,2); //调用函数
printf("%d",sum);
return 0;
}
4.函数的参数类型
函数的参数类型可以是任意数据类型。
当函数的参数类型是数组时,实参向形参传递的是数组首元素的地址,这种传递方式被称为“地址传递”。在内存中,实参和形参占用相同的存储单元。而在“值传递”中,实参和型参占用不同的存储单元,只是存储的值相同。
三、函数的嵌套调用
函数的定义是独立的,在一个函数中不能嵌套定义另外一个函数。但是,函数可以嵌套调用,即可以在一个函数中调用另一个函数。
#include <stdio.h>
void fun1(){
printf("我是fun1函数");
}
void fun2(){
printf("在fun2里面调用fun1函数\n");
fun1();
}
int main(){
fun2();
return 0;
}
运行结果
四、函数的递归调用
在函数的嵌套调用中,如果函数嵌套调用的是自己,这就是函数的递归调用。例如:
void fun(){
fun();
}
在调用fun函数时,又要调用fun函数,这就是fun函数的递归调用。但是,这里的fun函数的调用是无终止的,在程序中不应该出现。函数的递归调用必须要有终止条件,通常在函数定义时通过if语句控制。
例题:计算1~n之间的整数之和。
#include <stdio.h>
int add(int n){
if(n==1){
return 1;
}else{
return n+add(n-1);
}
}
int main(){
int sum;
sum=add(5); //计算1~5之间的和
printf("总和是%d",sum);
return 0;
}
分析:
运行结果为: 15
五、函数的声明
在前面的例子中,函数定义的位置是在该函数被调用之前。如果要把函数定义的位置放在调用它的函数的后面,应该在主调函数中进行函数的声明。函数的声明是把函数的信息(函数名、函数类型、参数个数和类型)提前通知编译系统,以便编译系统对程序进行编译时,检查被调用函数是否正确存在。
1.函数声明的方法
函数定义时的首行称为函数原型,函数声明时只需要在函数的原型后面加上“ ; ”。
例如: int add(int x,int y);
编译系统在检查函数调用时要求函数名、函数类型、参数个数和参数顺序必须与函数声明一致,实参类型必须与形参类型相同或赋值兼容。由于不检查参数名,因此在函数声明时,形参名可以省略。例如: int add( int ,int );
2.函数声明的位置
函数声明的位置有以下两种情况。
(1)函数声明在主调函数的外部。此时函数可以被声明之后出现的所有函数调用。例如:
#include <stdio.h>
int add(int ,int ); //声明在主函数外部
int main(){
int sum;
sum=add(2,2); //调用函数
printf("%d",sum);
return 0;
}
int add(int x,int y){
int result;
result = x + y;
return result;
}
(2)函数声明在主调函数的内部。此时函数只能被主调函数调用。例如:
#include <stdio.h>
int main(){
int add(int ,int ); //声明在主函数内部
int sum;
sum=add(2,2); //调用函数
printf("%d",sum);
return 0;
}
int add(int x,int y){
int result;
result = x + y;
return result;
}
六、变量的作用域和存储类别
C语言中的变量,按照其作用域范围可分为局部变量和全局变量。
1.局部变量
局部变量是指在函数内定义的变量,它的作用域是本函数内。也就是说,在函数的外部是不能使用这些变量的。此外,在函数内的复合语句内定义的变量也是局部变量,它的作用域是复合语句内。
2.全局变量
全局变量是指在函数外定义的变量,它的作用域是从定义处开始,到本程序文件的结束。也就是说,全局变量可以被文件中的所有函数所共用。