摘要:本文系统介绍了函数编程的核心概念,主要包括:1)函数的定义、调用和声明三种形式;2)变量的作用域(局部/全局变量)和生存周期;3)四种存储类型(auto/register/extern/static)及其内存分配机制;4)函数参数传递规则及递归函数的使用要点。重点解析了栈区、堆区、数据区和文本段的内存分布特点,通过闰年判断和四则运算实例演示函数封装方法,并以汉诺塔问题为例说明递归函数的应用逻辑。全文从理论到实践,系统阐述了函数编程的关键知识点。
一、函数的概要
1、作用:
避免重复性代码、让程序更加模块化;
2、三种形式:
函数的定义、函数的调用、函数的声明;
二、函数的定义
1、功能:定义一个函数的实现;
2、基本形式:
三、函数的调用
1、功能:跳转去使用一个函数
2、基本形式:
3、分类:
主调函数:主动调用别的函数的函数称为主调函数;
被调函数:被主调函数调用的函数称为被调函数;
四、函数的声明
1、功能:声明函数的参数及特性
2、要求:
(1)如果被调函数在主调函数的下方定义需要再主调函数上方声明
(2)如果被调函数在主调函数的上方定义,定义时已经完成函数的声明
五、变量的作用域和生存周期
(一)、作用域
1、定义:能够使用变量的范围称为变量的作用域
2、分类:
(1) 局部变量:变量作用域在离定义该变量最近的大括号内
(2) 全局变量:变量作用域在整个工程代码中,任意位置都可以使用全局变量
(二)、生存周期
1、定义:变量从开辟空间到空间被回收的过程称为生存周期
2、分类:
(1) 局部变量:
执行到变量定义时,为变量开辟内存空间;
代码执行超过变量作用域,回收变量空间;
(2) 全局变量:
编译时分配全局变量空间;
代码运行结束后回收变量空间;
(三)、存储类型
1、基本形式:存储类型 数据类型 变量名;
2、存储类型:
(1)auto(默认存储):自动型存储,将变量存放在栈空间中
(2)register:寄存器存储,将变量存放在CPU内部的寄存器中,如果寄存器存放等价于auto类型
(3)extern:声明一个变量是外部存放的
(4)static:静态存储,将变量存放在静态区中
3、代码运行时计算机内部空间分配:
具体内存区域
(1)栈区(.stack)
- 位于内核区域的上部,紧挨着内核的顶部。
- 栈区通常用于存储函数调用的局部变量、函数参数和返回地址等信息。
- 栈区空间有上限的,默认(8M),不要定义太大空间
栈区是操作系统管理区域,频繁被申请释放,所以未经初始化值为随机值
代码执行到变量定义时开辟空间(栈空间),代码执行超过变量作用域回收空间(栈空
间) - static关键字的作用:
- 如果用static修饰,会在程序结束时回收空间
- 延长变量的生存周期,局部变量超过作用域被回收
- static修饰变量,将变量存放在数据区中,未经初始化时值为0值
- static限定全局变量作用域只能在本文件中使用
- static防止全局变量或者全局函数重名
(2)堆区(.heap)
- 在栈区的下方。
- 堆区用于动态分配内存,通常在程序运行时根据需要分配
(3)数据区
- 特点:
存放全局变量和静态变量,未经初始化时会初始化为0值
程序编译时分配空间
程序结束时回收空间 - 包含三个子区域:
- .data:已初始化全局变量/静态变量区域(存放初始化的全局变量和静态变量)
- .bss:未初始化全局变量/静态变量区域(在程序运行时会对.bss端初始化为0值)
- .rodata:字符串常量区(区域中的内容不能修改,修改的话会导致段错)
- 这些区域用于存储程序中的全局变量和静态变量,其中.rodata通常用于存储只读数据。
(4)文本段(.text)
- 位于整个内存布局的最底部。
- 文本段通常用于存储程序的可执行代码,这部分内存区域在程序运行期间通常是只读的。
- 存放函数、代码和指令
如图所示:
六、函数调用
1、基本形式:函数名(实参1,实参2,....);
2、注意事项:
实参个数与形参个数需要匹配
实参与形参类型不一致时,会将实参类型转换为形参类
3、函数调用时参数的传递:
函数调用时实参会将值传递给形参(形参是实参的副本)
4、小试牛刀:封装一个函数传入一个年份,判断该年是否为闰年
个人注解:
- 先写c语言基本框架,头文件,main函数,返回值;
- 定义变量,题目判断是否为闰年,所以可以定义变量year;此外我们还需要定义一个变量接受封装函数的返回值(定义ret可以,也可以定义其他名good只为演示可同名也可不同名);good = 封装函数名IsleepYear(实际参数year)
- 开始写封装函数,先写好封装函数名和定义好形式参数,实际参数和形式参数对应。大括号内写满足闰年的条件,其次是函数结束后的返回值。
5、小试牛刀2:封装一个函数传入两个数字,计算加减乘除。
个人注解:
- 封装函数就相当于集成好的计算器,里面有我们能够实现各种功能的函数。当我们要计算时两个数相加,输入实际参数(num1,num2)选好能像实现其的功能函数名(add),即可得出结果。
- 现在我们就是承担编程好计算器功能,使它能够实现加减乘除的功能。
六、递归函数
1、 定义:函数体定义时调用函数体本身称为递归函数;
2、基本形式:
注意事项:
递归函数一定要有结束条件、避免深层次的递归调用
3、小试牛刀:汉诺塔盘子移动问题
个人注解:
先假设将5盘子从A移动到C,有个中间区域B可以使用。运用递归函数的话就慢慢简化,过程差不多就是我们先假设先把前四个盘子移动到B,剩下第五个盘子移到C(最后一个盘子最大,它放哪里都可以所以可以不用考虑)。这时我们就把前四个盘子移回A,要想把盘子都移动到C,按照刚刚的思考,我们就可以先把前三个盘子移动到B,剩下第四个盘子(在其他盘子中是最大的,放哪里都不影响,所以不用考虑),依次递归减下去。就可以简化问题。