一、函数浅析
1、函数
函数是一个可以反复使用的程序段,从其它的程序段中均可以通过调用语句来使用这个程序段,完成既定的工作
说明:
(1)建立函数称为“函数定义”,使用函数称为“函数调用”
(2)调用其它函数的函数称为“主调函数”,而被调用的函数称为“被调函数”
一个实用的C语言源程序总是由许多函数组成,这些函数都是根据实际任务,由用户自己来编写,在这些函数中可以调用C提供的库函数,也可以调用由用户自己或他人编写的函数。
但是,一个C语言源程序无论包含了多少函数,在正常情况下总是从main函数开始执行,main函数结束
C语言源程序可以分放在不同的文件中,所以一个源程序中的函数也可以分放在不同的文件中。
2、库函数
C语言提供了丰富的库函数,包括常用的数学函数、字符和字符串处理函数,输入输出函数等等。
调用C语言标准库函数时要求的include命令行
#include<stdio.h>
3、函数的定义
定义格式:
函数类型 函数名(形参类型说明表)
{
说明部分
语句部分
}
(1)函数有“函数头”和“函数体”两部分组成;函数体由语句和其他分程序组成
(2)函数类型规定了函数返回值的数据类型,若无返回值,则数据类型为void,如果函数有返回值,则在函数体中应有一条返回语句“return 表达式;”,无返回值,则返回语句应为“return;”也可以省略。
(3)形式参数表时逗号分隔的若干形式参数,每个形式参数可以时一个变量名、数组名、指针变量名和指针数组名,形参列表中每个参数的数据类型必须给出。
(4)形式参数可以为空,但是圆括号不能省略
(5)形参若是数组,只需给出数组名,[]中数组长度不许给出
(6)函数体中不允许再嵌套定义函数,能嵌套调用
函数返回值
函数的值通过return语句返回,return语句的形式如下:
return 表达式; 或 return (表达式);
说明:
(1)return语句中的表达式的值就是所求的函数值,此表达式的值的类型必须与函数首部所说明的类型一致。若类型不一致,则以函数值的类型为主,由系统自动转换。(可以写个函数测试以下)
(2)无论函数体中有多少个return语句,return语句只可能执行一次;
(3)return语句中可以不含表达式,这时必须定义函数为void类型。
(4)函数体内可以没有return语句,只是也必须定义函数为void类型。
函数调用
形式:函数名(实际参数表)
(1)没有返回值的函数调用格式:
函数名(实际参数表);
(2)有返回值的函数调用格式:
x=函数名(实际参数表);
二、函数的深析
1、基本思想:
将一个大程序按功能分割成一些小模块
特点:
各个模块相对独立、功能单一、结构清晰、接口简单
控制了程序的复杂性
提高原件的可靠性
缩短开发周期
避免程序开发的重复劳动
易于维护和功能扩充
开发方法
自上向下,逐步分解,分而治之
函数调用过程分析
(1)为函数的所有形参分配内存单元
(2)计算各个实参表达式的值,一一对应的赋值个相应的形参(若无形参,上述过程不执行)
(3)进入函数体,执行函数中的语句,实现函数的功能
(4)执行到return语句时,计算return语句中的表达式的值,(若无返回值函数,本项不做),返回到主调函数
(5)释放形参及本函数内的局部变量所占的内存,继续执行主调函数中的后继语句
2、函数间的传值
C语言中,主调函数和被调函数之间的数据可以通过三种方式进行传递
(1)值传递
值传递是个单向传递过程,两个单向传递构成双向传递
主调函数的内容传递给被调函数:
实际参数赋值给形式参数
(在C语言中,数据只能从实际参数单向传递给形参,俗称“按值”传递,用户不能再函数中改变对应实参的值)
被调函数的内容传给主调函数
通过return语句把内容赋给主调函数
1 #include<stdio.h> 2 int fun(int x,int y) 3 { 4 if(x==y) 5 return x; 6 else 7 return ((x+y)/2); 8 } 9 void main() 10 { 11 int a = 4,b=5,c=6; 12 printf("%d\n",fun(2*a,fun(b,c)));//值传递 13 return 0; 14 }
(2)地址传递
方式:函数调用时,将数据的存储地址作为参数传递给形参,当然此时的形参只能时存储地址的变量(指针变量)。才能达到“双向”传送的目的。
数组名可作为函数参数。(实参和形参都应用数组名)
(3)全局变量传递(这不是一种好的方式,通常不推荐使用)
3、函数的嵌套调用和递归调用
(1)函数的嵌套调用
函数甲调用了函数乙,而函数乙又调用了函数丙。C规定:函数定义不可嵌套,但可以嵌套调用函数。
(2)函数的递归调用
函数直接或间接的调用自身叫做函数的递归调用
递归的特点:
递归必须有递归结束条件;
递归过程首先是一级一级递推(即当前调用未结束又引出下一层调用),而满足递归结束条件时结束递推,再一级一级的回归(即一级一级再返回上一级的调用继续完成上一级的未完成的操作)。
说明:
C编译系统对递归函数的自调用次数没有限制,每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起堆栈溢出。
1 #include<stdio.h> 2 int fac(int n) 3 { 4 int t; 5 if(n == 1 || n ==0)//递归结束条件 6 return 1; 7 else 8 { 9 t = n*fac(n-1);//有规律地递减 10 return t;//返回上一层调用 11 } 12 } 13 void main() 14 { 15 int m, y; 16 printf("Enter m:"); 17 scanf("%d",&m); 18 if(m < 0) 19 printf("Input data error!\n"); 20 else 21 { 22 y = fac(m); 23 printf("\n%d! = %d\n",m,y); 24 } 25 return 0; 26 }
补充知识:
变量时对程序中数据的存储空间的抽象
(1)局部变量
定义:在函数内定义,只在函数内有效
使用:不同函数中同名变量占不同的存储单元
说明:形参属于局部变量
(2)全局变量
定义:在函数外面定义的变量
外部变量的作用域:对伊只有一个源程序文件构成的程序,外部变量的作用域时从定义它的位置开始,直至它所在源程序文件的结束
特点:外部变量的使用增加了函数之间传递数据的途径,在外部变量的作用域内的任何函数都能引用该外部变量,一个函数对外部变量的修改,能影响到其他引用这个变量的函数;因此对外部变量的使用不当,会产生意外的错误。