C语言函数

C语言函数,第1张

函数 形参与实参的关系:

​ 实参和形参位于不同的内存区域,彼此独立

​ 形参变量只有在函数被调用的时候,才会分配内存,在函数调用结束的时候,形参就会自动释放,所有的形参在函数体内有效的,不能在函数体外使用

​ 实参可以是变量、常量、表达式、函数调用,但是,如果是函数调用,要求在函数调用结束的时候,要有确定的值,以便于将这些值传递给函数做形参初始化, 实现给形参赋值。


int max(int x, int y)	//函数定义, x,y叫做形参
{
	return (x>y)?x:y;
}

int main(void)
{
	int x, y;
	scanf("%d%d", &x, &y);
	int m = max(x, y);	//调用函数,x,y叫做实参
//   int m = max(3,8);
//   int m = max(2, 4+8);
//   int m = max(x,func());//func函数要有确定的值
	printf("m = %d\n", m);

	return 0;
}

​ 实参和形参在数量上,类型上,顺序上必须要保持一致

​ 函数调用的时候,数据传输是单向的,不可逆

​ 函数调用的时候,多个形参在做初始化的时候,是按照从右往左的顺序初始化

函数调用的内存逻辑

​ 函数调用时,进程的上下文会切换到被调函数,当被调函数执行完之后,在切换回去

int main(void)
{
	int x, y;
	scanf("%d%d", &x, &y);
	int m = max(x, y);	//调用函数,x,y叫做实参
	printf("m = %d\n", m);
	return 0;
}

int max(int x, int y)//函数定义, x,y叫做形参
{	
	return (x>y)?x:y;
}

局部变量与栈内存

局部变量:定义在函数体内的变量(函数的形参也属于局部变量),就叫做局部变量

全局变量:定义在函数体外部的变量,全局变量在程序退出之前都是有效的。


​ 局部概念:只要是通过大括号括起来的变量,也称为局部变量

{
   	int b = 2;
}
   printf("b = %d\n", b);
这里不能打印b的值,b是属于上一个大括号里面的局部变量,出了这个大括号之后,b就被释放掉,变成无效的

局部变量的特点:

​ 某一函数内部的局部变量,存储在该函数的特定的栈内存中

​ 局部变量只能在该函数内可见,在该函数外部不可见

​ 当该函数退出后,局部变量所占的内存立即被系统回收,因此局部变量也被称为临时变量

​ 函数的形参虽然不被花括号包含,但依然属于该函数的局部变量

栈内存的特点:

​ 每当一个函数被调用时,系统将自动分配一段栈内存给该函数,用于存放其局部变量

​ 每当一个函数退出时,系统将自动回收其栈内存

​ 系统为函数分配栈内存的时候,是遵循从上(高地址)往下(低地址)的分配原则

技术要点:

​ 栈内存相对而言比较小的,不适合用来分配尺寸太大的变量

​ return之后不可再访问函数的局部变量,因此返回一个局部变量的地址通常是错误的

static关键字和静态函数 静态变量:

​ 用static关键字修饰的变量就叫做静态变量,比如 static int a;

​ static关键字修饰局部变量,这个变量从定义位置开始被分配到数据段里面,直接程序退出才会释放空间,并且这个变量只会初始化一次。


​ static关键字修饰全局变量,这个全局变量只在当前文件有效

static int m;	//让全局变量只在当前文件有效
int m;			//让全局变量被其他文件做外部声明

void func(void)
{
	static int a = 0;  //a只会被初始化一次,程序退出a才会被释放
	printf("a = %d\n", a++);
	return ;
}

int main(int argc, char const *argv[])
{
	func();//a = 0
	func();//a = 1
	func();//a = 2

	return 0;
}

静态函数:

​ 背景知识:普通函数都是跨文件使用的,即在a.c里面写的函数可以在b.c里面使用

​ 静态函数:用static修饰的函数,只能在定义的文件内可见的函数,称为静态函数

static void d_func(void)
{
	printf("这是个外部函数\n");
}

要点:

​ 静态函数主要是为了缩小函数的可见范围,减少与其他文件中重名函数冲突的概率

​ 静态函数一般定义在头文件中,然后被各个源文件包含

使用递归的条件

​ 子问题的逻辑与原问题一样,并且更为简单

​ 不能无限制重复调用本身,必须有一个出口,化简为非递归状态出来

设计一个递归算法

​ 确定问题变量

​ 确定递归公式(化简过程,比如n-1)

​ 确定边界条件

注意:递归是一个函数嵌套调用的过程,递归次数越多,运行时间会大幅度增加,内存空间也会大量占用,所以,一般能用循环解决的,我们就不考虑递归 缺点:效率低,还比较占内存 递归算法的一般应用

​ 数据的结构形式按照递归定义的(比如:二叉树)

​ 执行过程按照递归定义的(比如:函数的嵌套调用)

​ 问题的解决办法按照递归算法实现(比如:年龄问题,汉诺塔)

递归调用时,函数的栈内存会随着层层深入,栈空间就往下增长,如果递归的层次太深,很容易将栈内存耗光。


层层递进时,问题的规模会随之减小,减小到可直接退出的条件时,函数开始层层回归

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/634849.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-16
下一篇 2022-04-16

发表评论

登录后才能评论

评论列表(0条)

保存