【 05 函数 】

目录

  1. 函数的概念
  2. 库函数
  3. 自定义函数
  4. 形参和实参
  5. return语句
  6. 数组做函数参数
  7. 嵌套调用和链式访问
  8. 函数的声明和定义
  9. 编译静态库调用

1. 函数的概念

 函数 (funtion)也叫子程序,函数是完成某项特定任务的一段代码,c语言的程序由很多函数组成,一个大的任务可以拆分成许多函数,可以复用,提高了精简性和复用性

  • 库函数
  • 自定义函数

2. 库函数

2.1 标准库和头文件

c语言不提供库函数,规定了一些常用函数的标准。编译器根据标准实现,就是库函数
库函数可以直接使用,提升了效率。库函数的功能,在头文件中声明,可以在下网址查看:
https://zh.cppreference.com/w/cpp/standard_library

2.2 库函数的使用方法

库函数使用必须先包含对应的头文件
在上面网址查看库函数的说明:
在这里插入图片描述
以上内容包含:函数原型、功能说明、参数、返回值、注意事项、示例、输出结果、其他参阅

3. 自定义函数

自定义函数更加重要

3.2 语法形式

ret_type fun_name()
{
 函数实现
}
在这里插入图片描述

  • ret_type 表示函数计算结果的类型,可以是void,什么都不返回
  • fun_name 方便使用函数,要根据函数的功能取名,有意义
  • 函数的参数相当于工厂加工的原材料,可以是void,表示明确没有参数,如果什么都不写,调用的函数的时候可以随意传入,但不会产生数据
  • { } 括起来的是函数体,函数的实现内容

3.3 函数的举例

完成两个变量加法的函数

int Add(int x, int y)
{
 	int z = 0;
	 z = x+y;
	 return z;
}
int main()
{
	 int a = 0;
	 int b = 0;
	 //输⼊
	 scanf("%d %d", &a, &b);
	 //调⽤加法函数,完成a和b的相加
	 //求和的结果放在r中
	 int r = Add(a, b);
	 //输出
 printf("%d\n", r);
 return 0;
}

4. 形参和实参

上述代码在调用的时候传入的a和b就是实际参数,是真正参与计算的值
函数定义的时候的x和y是形式参数,因为不调用的话不会申请空间,不是真实存在的,调用的时候传入值,称为形式的实例化

实参和形参的关系
实参传递给形参,但这两个是独立的空间,地址是不一样的
在这里插入图片描述

5. return语句

注意事项:

  • 后面可以是数值也可以是表达式,如果是表达式先计算再返回
  • 可以什么都没有,直接return,这种是返回值类型为void
  • return返回的值和返回类型不一致,会隐式转换为返回类型
  • return执行后彻底返回,后面的代码不再执行
  • 如果有if语句,要保证每个条件都返回,否则会编译错误
  • 如果返回类型为void,可以返回值,但不能接收。如果返回为int,只写return,默认返回

6. 数组做函数参数

在自定义函数时,难免需要传入数组做参数,对数组进行操作。如果要传递数组,必须同时传递数组的元素个数,才能对数组遍历

  • 函数的形参和实参个数匹配
  • 实参和形参都可以写成数组形式
  • 形参如果是一维数组,数组大小可以省略不写
  • 形参如果是二维数组,行可以省略,列不可以
  • 数组传参,形参不会创建新的数组
  • 形参和实参操作的是统一数组

7.嵌套调用和链式访问

7.1 嵌套调用

嵌套调用就是函数之间的互相调用

int is_leap_year(int y)
{
 if(((y%4==0)&&(y%100!=0))||(y%400==0))
 return 1;
 else
 return 0;
}
int get_days_of_month(int y, int m)
{
 int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 int day = days[m];
 if (is_leap_year(y) && m == 2)
 day += 1;
 
 return day;
}
int main()
{
 int y = 0;
 int m = 0;
 scanf("%d %d", &y, &m);
 int d = get_days_of_month(y, m);
 printf("%d\n", d);
 return 0;
}

main函数调用了scanf、printf、get_days_of_month
get_days_of_month调用了is_leap_year

7.2 链式访问

将函数的返回值作为参数

#include <stdio.h>
int main()
{
 printf("%d\n", strlen("abcdef"));//链式访问
 return 0;
}

strlen的返回值作为printf的参数
printf("%d", printf("%d", printf("%d", 43)));
这个代码会打印多少呢?
首先了解一下printf的返回值,返回打印在屏幕上的字符个数
最里层的pirntf先打印43,然后返回成功打印2个字符,然后打印这个返回值,继续返回打印成功1个,最后打印1。所以最终结果: 4321

8. 函数的声明和定义

函数的定义,如果函数在调用时后面定义就会报错,这时需要在调用前声明函数,函数声明需要写出函数的返回值类型、函数名、参数,然后加个分号就行了

//函数声明
void ptt(int arr[]);
int main()
{
	
	int n = 4;
	int ary[3] = { 1,2 };
	ptt(ary);
	printf("%d", n);
	return 0;
}
void ptt(int arr[]) {
	return 5;
}

一般将函数定义在调用前,可以不用声明

8.2 多个文件

代码较多时,函数的声明、类型放在头文件(.h)中,实现放在源文件(.c)中,
在这里插入图片描述
函数声明在头文件,实现在对应的源文件,主函数使用的时候直接调用,实现和使用都需要包含对应头文件

8.3 static和extern

都是c语言的关键字,static是静态的意思

  • 修饰局部变量
  • 修饰全局变量
  • 修饰函数

extern是声明外部符号的
在讲解这两个符号之前,先说一下作用域和生命周期

作用域(scope): 程序设计概念,一段代码用的名字并不总是有效的,限定这个名字可用的范围就是作用域

  1. 局部变量的作用域是变量所在的局部范围
  2. 全局变量的作用域是整个工程(项目)

生命周期: 变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段

  1. 局部变量的生命周期: 进入作用域创建变量,生命周期开始,出作用域生命周期结束
  2. 全局变量的生命周期: 整个程序的生命周期

8.4 static修饰的局部变量

在这里插入图片描述

 对比两个代码,左边的打印的都是2,右边的是2,3,4,5
代码1: 变量i在每次进入test函数后会重新创建,并赋值为0,然后++再打印,存放在栈区,是临时的,出函数后生命周期就结束(释放内存)
代码2: i值会累加,所以i值创建好后出函数不会销毁,static修饰后存放在静态区

static修饰局部变量
本质上影响了变量的存储类型,存到了静态区,生命周期变长了,作用域不变

8.5 static修饰全局变量

在这里插入图片描述
全局变量具有外部链接属性,想在另一个c文件使用需要extern来声明外部符号。但用了static修饰后,变成了内部连接属性,只能在本文件使用
如果一个变量只想在本文件内部使用,不想被其他文件用,可以用static修饰

8.6 extern声明函数

如果一个另一个文件的函数想在main文件或其他文件使用,可以直接调用,因为函数默认具有外部链接属性,但会报警告错误,因为这个文件并不认识另一个文件的函数,所以完整的写法,应该用exterm来声明外部的函数。如果用static修饰函数,这个函数也成了内部连接属性,一般用来只在本文件使用的函数这样定义,不需要被其他文件使用,方便函数隐藏

9.编译静态库调用

项目属性→配置类型→改为lib静态库
在这里插入图片描述
在这里插入图片描述
该文件内容查看为乱码,为了让别人能看懂,将。h声明文件也一起放到需要的工程目录下,加上导入静态库的代码
在这里插入图片描述

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值