目录
一、概述:
- 函数就是功能,每一个函数用来实现一个特定的功能,函数的名字应反应其代表的功能。
- C源程序是由函数组成的。函数是C源程序的基本模块,通过对函数模块的调用实现特定的功能。C程序的全部工作都是由各式各样的两数完成的,所以也把C语言称为两数式语言。由于采用了函数模块式的结构,C语言易于实现结构化程序设计。使程序的层次结构清晰,便于程序的编写、阅读、调试。
- 一个源程序文件可由一个或多个函数组成,一个C语言程序可以由一个或多个源程序代码组成。
- C语言执行总是从main函数开始,如果在main函数中调用其他函数,在调用后流程返回带main函数,在main函数中结束整个程序的运行。
- 所有函数都是平行的,即在定义函数时是分别进行的,是相互独立的。一个函数并不从属于另一个函数,即函数不能嵌套定义。函数间可以相互调用,但不能调用main函数,main函数是被操作系统调用的。
1、函数的分类:
从用户使用的角度看,函数可以分为系统函数和用户自定义函数两种:
- ①系统函数:即库函数,有编译系统提供的,用户不必自己定义这些函数,可以直接使用(记得加头文件)
- ②用户自定义函数:用来满足用户专门需要,由用户按需要写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。
从函数的形式看,函数可以分为无参函数和有参函数两种:
- ①无参函数:函数定义、函数说明及函数调用中均不带参数。在调用无参函数时,主调函数不向被调函数传递数据,无参函数一般用来执行指定的一组操作。
- ②有参函数:在函数定义及函数说明时都有参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,称为实际参数(简称为实参)。在调用有参函数时,主调函数在调用被调用函数时,通过参数向被调函数传递数据。
从功能看,函数分为有返回值函数和无返回值函数两种:
- ①有返回值函数:此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值。由用户定义的这种要返回函数值的函数,必须在函数定义和函数说明中明确返回值的类型。
- ②无返回值函数:此类函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。由于函数无须返回值,用户在定义此类函数时可指定它的返回为 “空类型”,空类型的说明符为 “void”。
2、函数形参和实参的特点:
函数的形参和实参具有以下特点:
- 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
- 实参可以是常量、麥量、表达式、两数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应 预先用赋值,输入等办法使实参获得确定值。
- 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。
- 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
3、函数的作用:
①函数的使用可以省去重复代码的编写,降低代码重复率(降低冗余)
②函数可以让程序更加模块化,有利于程序的阅读、修改和完善
二、函数的定义及使用:
C语言中要求在程序中用到的所有函数必须先定义,后使用(库函数由编译系统事先定义好了,不需要用户自己定义,只需引入头文件即可),定义函数应包含以下几个内容:
①指定函数名字,以便以后按名调用
②指定函数类型,即函数返回值类型
③指定函数的参数的名字和类型,以便在调用函数时向它们传递数据,对无参函数不需要
④指定函数功能,在函数体中进行
(一)定义函数的方法:“头+体”
1、定义无参函数:
类型名 函数名( )
{
函数体
}
或
类型名 函数名(void)
{
函数体
}
如:
void print_star()
{
printf("******\n");
}
2、定义有参函数:
类型名 函数名(形式参数表列)
{
函数体
}
如:
int max(int x,int y)
{
int z;
z = x > y ? x : y;
return(z);
}
3、定义空函数:
类型名 函数名( )
{ }
void dummy()
{}
4.注意:
①函数体可以没有语句,但是不能省略{},函数名后必须有()
②定义有参函数时,形参的定义可以采用“传统方式”或“现代方式”:
如传统方式:
int max(x,y) int x,y; //此处不能定义形参以外的其他变量 { 函数体 }
现代方式:
int max(int x,int y) { 函数体 }
定义函数时必须采用上面两种方式之一指定参数类型
int max(x,y)
{
函数体
} 是错误的③函数返回值类型:两类
形式一:非void型
类型名 函数名(参数表列) //类型名包括int;float;char 等 { '''' return 表达式; //return 表达式; 先计算后返回值 }
形式二:void型:
void 函数名(参数列表) { ..... //不需要加return语句,在有些编译器中加了不报错,有些编译器报错 }
(二)函数调用形式:
函数调用的一般形式为:
- 非void型: 变量名=函数名(实参表列)
- void型:函数名(实参表列)
按函数调用在程序中出现的形式和位置来分可以以下三种函数调用方式:
1.函数调用语句:把函数调用单独作为一个语句,如:
print_star();
2.函数表达式:函数调用出现在另一个表达式中,他是赋值表达式中的一部分,这时要求函数带回一个确定的值以参加以表达式的运算。如:
c = 2 * max(a,b);
3.函数参数:函数调用作为另一个函数调用时的实参。如:
m = max(a,max(b,c));
注意:调用函数并不一定要求包括分号,只有作为函数调用语句才需要有分号,如果作为函数表达式或函数参数函数,调用本身是不必有分号的。如写成以下这样是不对的:
printf("%d",max(a,b););
(三)函数调用时的数据传递:
1、形式参数(形参)和实际参数(实参):
- 在定义函数时,函数名后面括号中的变量名称为形式参数或虚拟参数。
- 在主调函数中调用一个函数时,函数名后面括号中的参数称为实际参数,实际参数可以是常量、变量或表达式。
- 在定义函数中指定的形参在未出现函数调用时,他们并不占内存中的存储单元。在发生函数调用时,形参被临时分配内存单元。调用结束形参单元被释放,实参单元仍保留并维持原值没有改变。
- 如果在执行一个被调用函数时,形参的值发生改变不会改变主调函数的实参的值。
2、实参和形参间的数据传递:
- 在调用有参函数时,主调函数和被调函数之间有数据传递关系。
- 在调用函数过程中,系统会把实参的值传递给被调用函数的形参,或者说是形参从实参得到一个值,该值在函数调用期间有效,可以参加该函数中的运算。
- 在调用函数过程中发生的实参与形参间的数据传递常称为”虚实结合“。
- 传参遵循单向传值(实参传递给形参),三一致(个数、类型、位置次序)原则
三、对被调用函数的声明和函数原型:
在一个函数中调用另一个函数(即被调用函数)需要具备如下条件:
- ①首先被调用的函数必须是已经定义的函数(库函数或用户自定义的函数)
- ②如果使用库函数应该在开头引入对应头文件
- ③如果使用用户自己定义的函数,而该函数的位置在调用他的函数(即主函数)的后面,应该在主调函数中对被调用的函数做说明,说明的作用是把函数名,函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法
函数定义中的”函数头“(函数首部)称为函数原型。常用函数首部来作为函数声明是为了便于对函数调用的合法性进行检查。
函数声明有两种方式:
① 库函数:#include <头文件>
② 用户自定义函数(子函数在上主函数在下时不需要):
- 函数类型 函数名(形参类型1 形参1,形参类型2 形参2,……);
- 函数类型 函数名(形参类型1 ,形参类型2 ,……);
四、区别函数定义、声明、调用口诀:
头:函数头 体:函数体
- 有头有体无份号——函数定义
- 有头无体有分号——函数原型声明
- 函数名()——函数调用