1定义:
在C语言中,函数是一段具有特定功能的独立代码块,它可以接收输入参数、执行相关操作并返回结果。
2为什么需要函数
(1)代码复用:避免重复编写相同功能的代码, (2)模块化设计:将复杂程序分成多个小功能模块,每个函数负责一个独立任务,使代码逻辑结构更加清晰。一般一个函数的代码在50行左右 (3)好处:便于维护和调试(单个函数功能单一,出现问题容易定位和修改,不需要改动整个程序。 (4)提高开发效率:便于多人协同开发时,分工明确,编写不同函数,最终组合成完整程序。
3、函数的声明
(1) 基本语法
函数声明:返回类型 函数名(形参列表);函数首部+分号就是函数声明,只有函数声明而没有函数定义会编译报错
函数定义: 在函数声明的基础上添加函数体
返回类型 函数名(形参列表) { //函数体 } 只有函数定义而没有函数声明可能会编译警告或出错(函数声明可以忽略不写) 函数定义一般写在源文件中 .c.cpp
(2)分析语法
1> 返回类型 i. 数组不可以做函数的返回类型(弱化为指针) i.如果函数不需要任何返回值,则返回类型写为 void i.函数中,主要返回类型不是void,就一定需要用到return(若没有则有隐藏bug) i.如果返回类型是void,也可以使用return,通常书写形式为:return;只是用来结束当前函数 i.必须要确保函数全域返回。 2>函数名 i.与变量的命名规则一致(企业要求) i.>在C语言中,函数名也是函数的起始地址,函数名通过printf输出(十六进制) i.>在C语言中,不允许出现同名函数(c++例外) 3>形参列表 1.>在函数定义或声明时,函数首部中的函数称为形参(临时,调用完成后消失) i.在函数被调用时,其传递的参数称为实参,实参不带有类型 i.函数参数根据实际情况,可有可无,通常要求形参个数不超过5个。 形参和实参不仅个数和类型一一完全匹配。 多个参数之间需要通过逗号分隔 多个形参,其每个形参需要独立的类型,不能进行合并 参数分为:入参,出参,出入参 入参:从实参到形参的单向只传递(从内存角度看) 出参:能将数据通过参数带回给函数调用处 函数的参数可以是不固定个数,也可以是可变参数 实参变量名可以和形参不一样
函数传参的形式
值传递:单向值传递
指针传递
引用传递(C++)
(3)内存布局
栈区,堆区,全局/静态数据区、文本区、常量区
栈区:局部变量、函数形参
特点:由编译器自动分配和释放。遵循"先进后出"原则
堆区:通过malloc等函数动态开辟、Free动态释放的内存
全局/静态数据区:存储全局或静态数据
文本区:主要针对代码
常量区:主要存储代码
栈区,堆区、数据段(初始化数据段,未初始化数据段)、代码段
静态初始化变量只初始化一次,存在全局/静态数据区
(4)参数调用过程
A.参数压栈(保存相关数据信息
在函数调用前,先将参数从右到左的顺序如栈。先进后出
比如fun(a,b,c);先入栈c,后入栈b,最后入栈a
B.保存现场
保存当前函数的寄存器
C.挑战到被调函数
开始执行函数体
D.栈帧创建
被调函数先保存调用函数的栈基址,然后在创建自己的基地址,用于定位局部变量和参数
E.执行函数体
F.结果返回
函数中执行return时,将返回值保存在eax中。释放局部变量的栈空间,恢复调用函数的栈基址和寄存器等。
G.恢复现场
从栈中取出返回值,跳转回调用函数的下一条指令。
除去返回值
入栈,出栈
代码如下
#include <stdio.h>
`int main()
{
long long num1 = 0xAAAAAAAA;
long long num2 = 0xBBBBBBBBCCCCCCCC;
long long num3 = 0xDDDDDDDD;
printf("%p, %p, %p\n", num1, num2, num3);
}