【笔记】【C语言】第七章 用函数实现模块化程序设计
- 函数的概念
- 函数的定义与调用
- 函数的递归调用
- 变量的作用域
- 函数的作用域
7.1 函数的作用
(1)函数的作用
将 较大的程序 划分为若干个 程序模块。每个模块实现一个特定的功能。
在高级语言中,用子程序实现模块功能。
函数间的调用关系:同一个函数可以被一个或多个函数调用任意次。
(2)
一个C程序 由一个或多个程序模块组成。
每个程序模块 作为一个源程序文件。
(3)
一个源程序文件 由一个或多个 函数以及其他内容(命令行、数据定义等)组成。
一个源程序文件 是一个编译单位。
(4)
C程序执行从main函数开始,在main函数结束。
函数之间平行。即定义时不能嵌套定义。
函数间不能嵌套定义。可以相互调用,但不能调用main函数。 (main函数由系统调用)
(5)
使用角度,分为:
- 标准函数(库函数):由系统提供。
- 用户自己定义的函数
函数形式,分为:
- 无参函数
- 有参函数:主调函数 向 被调用函数 传递数据。
7.2 定义函数
(0)对函数功能的确立
(1)一般形式
类型标识符 函数名 ( 形式参数表列 ) { 声明部分 语句部分 return () ; }
(2)形式参数 实际参数 函数返回值
定义函数时,称为形式参数。在主调函数中调用时,称为实际参数。
return () ; 后的值作为函数带回的值(不需要函数返回值,可以不写return 语句)
在不同的函数间,传输数据——参数,返回值,全局变量
(3)
形参在未被调用时,不占存储单元。
只有在调用时,才被分配内存单元,调用结束后,所占的内存单元被释放。
(4)
实参可以使常量、变量、表达式。但要求有确定的值。
与形参的类型应该相同或者赋值兼容。
字符型与整型可以互相通用。
实参与形参对数据的传递是“值传递”。
(5)
函数的返回值应该属于某一个确定的类型。 若是定义时指定类型,应该符合。
在C语言中,凡是不加类型说明的函数,自动按 整型 处理。
若return 中表达式的值 与函数类型 不同,以函数类型为准。
7.3 函数调用
(1)一般形式:函数名(实参列表)
(2)对实参的求值顺序,各系统并不一致。
(3)调用方式:
- 函数(作为)语句
- 函数表达式
- 函数参数(实际同2)
(4)声明:把函数名和函数参数的个数及函数参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确认识函数并检查函数调用是否合法。
库函数:文件开头用#include 命令,将调用有关库函数时所需用到的信息“包含”到本文件中。
自己定义的函数:应在主调函数中 对被调函数作声明。
若被调函数定义出现在主调函数前,则不用声明。
(5)
C语言不能嵌套定义函数,但可以嵌套调用
(6)递归调用:
在调用一个函数的过程中,直接或间接地调用该函数本身,称为函数的递归调用。
基本条件:用于控制递归调用结束。每个递归函数必须至少有一个基本条件,能用非递归的计算方式得到。
一般条件:控制递归调用向着基本条件的方向转换。一般条件必须最终能转化为基本条件。
7.7 数组 作为函数参数
(1)数组元素 可以作为 实参,单向传递(值传递)。
(2)数组名 作为 实参。此时形参应当用数组名/指针变量。
可以不定义长度。
例如:
float average ( float arr[ ] , int n )
引用时:average ( a , a_len ) 或者 average ( &a[0] , a_len )
float average ( float arr[10] , int n )
float average ( float * g )
(3)多维数组名 作为 实参。
与初始化的规则较为相似,
(5)二维数组
如果对全部元素都赋初值,则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。
int a[3][4]或者 int a[][4]
引用也是如此。
7.8 局部变量和全局变量
(1)内部变量:
在函数内部定义的变量。作用范围只有定义后 到 函数内部。
外部变量:
在函数外定义的变量。全局变量可以为 本文件 中的其他函数所共用。有效范围:定义位置 到 本源文件结束。
(2)不同函数中可以使用相同名字的变量,代表不同的对象。他们在内存中占用不同的单元。
(3)形参也是局部变量。
(4)在一个函数内部,可以在复合语句中定义变量,
这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”。
(5)建议限制使用变量,将函数做成封闭体。
①全局变量在程序的全部执行过程中,都占用 存储单元 。
局部变量尽在需要时才 开辟单元 。
②全局变量过多,会降低程序的清晰性,难以判断全局变量的值。
③降低了函数的通用性,移植函数时还需要移植有关的外部变量及其值。
④降低了可靠性,可能出现同名变量。
(非考试重点)
7.9 变量的存储类别
(1)从变量作用域(空间)角度,分为局部变量,全局变量。
从变量值存在的时间(生存期)角度,分为静态/动态存储方法。
(2)动态存储方式:在程序运行期间,根据需要进行动态的分配存储空间的方式
静态存储方式:在程序运行期间,由系统分配固定的存储空间的方式。
(3)存储空间分为:
- 程序区
- 静态存储区
- 动态存储区
(4)C中变量/函数 有两个属性:数据类型 和 数据的存储类别。
(5)存储类别:静态存储类 动态存储类:
自动的(auto) :自动变量
函数中的局部变量,未声明static存储类别,都是动态分配存储空间,数据存储在动态存储区。
在调用该函数的时候,系统会给他们分配存储空间,调用结束,自动释放这些空间。
未赋值则值不确定,因为下次重新另外分配空间,分配的单元中的值是不确定的。
静态的(static):
有时需要保留函数中局部变量的值,则指定该局部变量为“静态局部变量”。数据存储在静态存储区。
静态局部变量实在编译时进行赋值,往后函数调用时,每次重新进行一次赋值语句。
若是未定义初值,则编译时自动赋初值为0/空字符。
静态局部变量结束后仍存在,但其他函数不能引用他们。
寄存器的(register):寄存器变量
一般情况,变量存储在内存中。当程序需要使用时,由控制器发出指令将内存中该变量的值送到运算器中。经过运算后,若要存储,再从运算器将数据送到内存中存放。
如果某变量使用频繁,则可以将局部变量的值存放在CPU中的寄存器中,需要时直接从寄存器中存取。
外部的(extern):外部变量
作用域是从定义处开始,到本程序文件的末尾。用extern声明外部变量,以扩展外部变量的作用域。
(6)用static声明外部变量
外部变量,但只限于本文件引用。
static使全局变量局部化,局限于本文件内。
(7)变量的声明和定义
建立存储空间的声明,称为定义;不需要建立存储空间的声明,称为定义。(此处声明为狭义,指非定义性声明)
(8)存储类别小结:
从作用域分:
局部变量:
自动变量(离开函数,值就消失)
静态局部变量(离开函数,值仍保留)
寄存器变量(离开函数,值就消失)
全局变量:
静态外部变量(只限文本引用)
外部变量(允许其他文件引用)
从生存期分:
动态存储:
自动变量(本函数有效)
寄存器变量(本函数有效)
形式参数(本函数有效)
静态存储:
静态局部变量(函数内有效)
静态外部变量(本文件有效)
外部变量(其他文件可引用)
从变量值存储的位置区分:
内存中静态存储区:
静态局部变量
静态外部变量(函数外部静态变量)
外部变量(可为其他文件引用)
内存中动态存储区:
自动变量和形式参数
CPU中寄存器:
寄存器变量
7.10 内部函数 和 外部函数
(1)函数的本质是全局的,也可以指定函数不能被其他文件调用。
(2)内部函数:
一个函数只能被本文件中其他函数所调用。
static 类型标识符 函数名(形参表)
(3)外部函数:
可供其他文件调用。 默认外部函数。
extern 类型标识符 函数名 (形参表)