C语言函数

函数的概念

函数的概念:就是一堆语句的组合,一次写好,到处使用!如:printf函数
函数的本质目的:减少开发的工作量,提高代码的可维护性。
C语言中可以对语句进行分组管理,每个语句分组叫做一个函数

int main(void){
	printf("hello,world\n");
		//此时CPU会跳转到printf函数定义的部分
		//接下来从上到下执行printf函数的语句,执行结束
		//返回到当前位置
	return 0;
}

函数调用 - 使用已经定义好的函数
被使用的函数称为被调用函数 - printf函数
使用被调用函数的函数被称为调用函数 - main函数
函数调用三步骤:跳转–执行–返回(从哪跳转,到哪返回)

函数的定义–函数的实现

返回值类型 函数名(形参表){
函数体;
}
返回值数据类型
形参表 - 用来存储给函数的数据

函数的调用过程中通常伴随着两个函数之间的数据传递
数据传递存在两个完全相反的方向:
可以从调用函数向被调用函数传递数据 – 参数
可以从被调用函数向调用函数传递数据 – 返回值
在这里插入图片描述

函数的返回值

只能从被调用函数向调用函数传递的一个数据,这个数据叫做被调用函数的返回值
返回值必须记录在被调用函数的存储区里,编写函数的时候要把这个存储区的类型名称写在函数名称前面
被调用函数里使用return关键字指定作为返回值的数值
调用函数里要把整个函数调用语句当作数字使用,整个数字就是被调用函数的返回值
在这里插入图片描述

#include<stdio.h>
//函数定义
//没有参数,没有返回值
void foo(void){
	printf("void foo(void);\n");
}
void foo(void){
	printf("void foo(void);\n");
	return;	//只表示函数结束,没有返回值
	printf("how are you\n");	//不会执行
}
//没有参数,具有返回值
int bar(void){
	return 520;	//给调用函数传递数据520,是int类型数据
}
int bar1(void){
	int a = 520;
	return a;	//将变量a的值返回给调用函数
}
int bar2(void){
	int b = 100;
	//return b;	//本来要执行语句,忘写了
}	//返回随机数
char bar3(void){
	int c = 300;
	return c;	//会将c先转换成char类型的数据,然后再返回,数据丢失
}

int main(void){
	
	int ret = 0;
	ret = bar1();
	printf("bar1() = %d\n", ret);	// 520
	ret = bar2();
	printf("bar2() = %d\n", ret);	// 17(随机数)
	ret = bar3();
	printf("bar3() = %d\n", ret);	// 44
	//main函数调用bar函数,bar函数会给main函数一个返回值,是int类型的数据
	//定义了变量ret来存储bar函数给main函数的返回值(数据)
	//main - 调用函数
	//使用函数调用语句表示返回值
	
	return 0;
}

函数的参数

可以从调用函数向被调用函数传递多个数据,这些数据的类型可以不同
被调用函数需要为每一个传递过来的数据提供一个存储区
编写函数的时候需要在函数名称后面的小括号声明一组变量,这些变量就用来表示前面提到的存储区,这些变量叫做形式参数,小括号里的所有内容叫做形式参数列表
调用带有参数的函数时需要在函数调用语句的小括号里为每个形式参数提供一个对应的数字,计算机会把这些数字记录到对应的形式参数里。被调用函数可以通过形式参数得到这些数字。这些数字叫做实际参数
只要能当作数字使用的内容都可以作为实际参数使用

调用函数:
调用关系 + 调用函数给被调用函数传数据
main函数调用add函数,并且将变量a和b的值传递给add函数
如果想要将数据传递给被调用函数,直接将要传递的数据写在调用语句的圆括号中,add(a, b) - 将要传递的值放到圆括号即可,使用逗号将数据隔开

被调用函数:
被调用函数获取数据后,需要提供对应的存储区将调用函数传递的数据存储起来,如何存储呢?
需要在定义函数的时候,在函数名小括号中写上对应的存储区
此时提供两个int类型的存储区,并且提供两个存储区的名字
void add(int x, int y){ … }
此次的数据传输,就是将a的值赋值给了变量x,b的值赋值给了y。

#include<stdio.h>

//有参数,没有返回值
void add(int x, int y){
	printf("x + y = %d\n", x+y);  //30
}
//有参数,有返回值
int sub(int m, int n){
	return m - n;
}

int main(void){
	int ret = 0;
	int a = 10, b = 20;
	add(a, b);	//调用add函数 + 将a和b的值传递给了add函数;输出30
	ret = sub(a, b);  //main函数将a的值给m,将b的值给n
	printf("sub(10, 20) = %d\n", ret);  // -10

	return 0;
}

函数的声明

告诉编译器,有这个函数的定义,暂时找不到先别报错,再找找
任何函数都可以分为大括号前面部分和大括号里面部分
函数大括号前面的部分可以单独写成一条语句,这种语句叫做函数声明语句
函数声明语句里可以省略形式参数名称
把函数声明语句写在文件开头叫做函数的显示声明
除了主函数外的所有函数都应进行显式声明
格式:extern 返回值 函数名(形参列表);
函数的定义在函数的调用前面,可以省略函数声明

#include<stdio.h>
extern void add( int x, int y);   	//函数的定义在其他地方,找不到先不要报错

int main(void){
	int ret = 0;
	int a = 10, b = 20;
	add(a, b);	//调用add函数 + 将a和b的值传递给了add函数;输出30

	return 0;
}

void add(int x, int y){
	printf("x + y = %d\n", x+y);  
}

递归函数

C语言中函数可以调用自己,自己调用自己的函数叫递归函数
函数A -> 函数B; 函数A -> 函数A
如果一个问题可以采用同样的方法不停的分解并且分解后的问题一定比原来的问题更简单,这种问题就可以采用递归函数解决。

#include <stdio.h>
void foo(void){
	printf("hello\n");
	foo();
}
int main(void){
	foo();
	return 0;
}

递归函数的编写步骤:
单独编写语句解决分解后的每个小问题(假设递归函数已经可以使用了)
在递归调用语句前编写分支处理不可分解的情况(这种分支必须要能结束函数)

#include<stdio.h>
//递归函数
//实现功能 - 1 2 3 4 5 ... n
void p(int n){
	if(1 == n){
		printf("1");
		return; //结束函数
	}
	//假设函数可以使用
	//p(n) == p(n-1) + printf("n")
	p(n-1);
	printf("%d", n);
}
int main(void){
	return 0;
}

变量的作用域和生命周期

能使用某个变量的所有语句叫做变量的作用域;生命周期是一段时间,在生命周期开始的时候计算机给程序分配存储区,在生命周期结束的时候计算机把分配给程序的存储区收回
【局部变量】 - 定义在函数内的变量
作用域:定义的位置开始到函数结束
生命周期:函数某一次执行的时间范围

#include<stdio.h>
//调用函数的时候为形参分配存储区,函数结束的时候释放存储区
void swap(int x, int y){
	int tem = x;
	x = y;
	y = temp; 
}
int main(void){
	int var = 1024;  //局部变量;定义的时候分配存储区,函数结束释放存储区
	printf("var = %d\n", var);  //ok
	if(1024 == var){
		int var1 = 2048;  //局部变量 - 块级变量;作用域:定义开始向下,直到花括号结束;声明周期:定义的时候分配存储区,遇到大括号释放
		printf("val = %d\n", val1);
	}
	return 0;
}

【全局变量】 - 定义在函数外的变量
作用域:从定义的位置开始向下的所有语句
生命周期:整个程序的执行时间

#include<stdio.h>
void A(void){
	printf("A:g_var = %d\n", g_var);  //error
}
int g_var = 520;  //全局变量,g_ = global
int g_var2;  //不初始化全局变量,默认为0
int main(void){
	printf("main:g_var = %d\n", g_var);  //ok
	return 0;
}
int g_var1 = 1024;  //全局变量,main函数不能用

全局变量可以和局部变量重名 - 优先使用局部变量

【静态变量】
静态变量的生命周期和作用域与普通变量的不一样,静态变量的生命周期是整个程序执行时间
声明静态变量的时候需要使用static关键字
没有初始化的静态变量会自动被初始化成0
函数结束后静态局部变量和存储区也还是可以使用
静态局部变量的初始化只在程序开始的时候执行一次,不论初始化语句写在什么地方
静态全局变量的生命周期还是整个程序的执行时间,但是它的作用域只包含声明它的文件里的所有语句(不可以跨文件使用静态全局变量)

练习

#include<stdio.h>  //standard input output header
#include<stdlib.h>  //standard library header, exit

double g_balance = 0;  //余额
double g_rate = 0.01;  //利率

//定义菜单显示的函数
int menu(void){
	printf("---------------------------\n");
	printf("        mini银行\n");
	printf("---------------------------\n");
	printf("[1]清空账户\n");
	printf("[2]存款\n");
	printf("[3]取款\n");
	printf("[4]查询余额\n");
	printf("[5]利息结算\n");
	printf("[6]调整利率\n");
	printf("[0]退出\n");
	printf("---------------------------\n");
	printf("请选择:");
	int select = -1;
	scanf("%d", &select);
	return select;
}
//定义查询余额函数
void query(void){
	printf("当前余额:%lg\n", g_balance);
}
//清空账号
void clear(void){
	g_balance = 0;
	query();
}
//存款函数
void save(void){
	printf("存款金额:");
	double Save;
	scanf("%lg", &Save);
	g_balance += Save;
	query();
}
//取款函数
viod get(void){
	printf("取款金额:");
	double Get;
	scanf("%lg", &Get);
	if(Get > g_balance)
		printf("余额不足\n");
	else{
		g_balance -= Get;
		query();
	}
}
//利息结算
void settle(void){
	g_balance *= (1 + g_rate);
	query();
}
//利率调整
void adjust(void){
	printf("当前利率:%lg\n", g_rate);
	printf("调整后利率:");
	scanf("%lg", &g_rate);
}
//定义退出程序函数
void quit(void){
	printf("谢谢使用,再见\n");
	exit(0); //标准C库函数,结束当前程序
}

int main(void){
	for(;;){
		switch(menu()){
			case 1:
				clear();
				break;
			case 2:
				save();
				break;
			case 3:
				get();
				break;
			case 4:
				query();
				break;
			case 5:
				settle();
				break;
			case 6:
				adjust();
				break;
			case 0:
				quit();
				break;
			default:
				printf("选择错误。\n");
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值