当前位置: 首页 > news >正文

从上帝视角看函数

1.函数的概念

函数(function),有的地方翻译为子程序。C语言中的函数就是完成某项特定的任务的⼀段代码。C语言的程序其实是由无数个小的函数组合而成的,也可以说:⼀个大的计算任务可以分解成若⼲个较小的函数(对应较小的任务)完成。同时⼀个函数如果能完成某项特定任务的话,这个函数也是可以反复使用的,提升了软件的开发效率。
在这里插入图片描述

2.库函数

2.1:为了不再重复写常见的代码(如写一个函数按照某种格式在屏幕上打印信息、写一个函数求字符串的长度),提高程序员的开发效率,C语言标准(ANSI)规定了一些函数(每个函数都规定了函数名、返回值类型、形式参数以及函数功能),再由不同的编译器厂商根据该规定实现这些函数,提供给程序员使用。这些函数组成了一个函数库,称为标准库,这些函数就被称为库函数。 在这个基础上⼀些编译器厂商可能会额外扩展提供部分函数(这些函数其他编译器不一定支持)。

2.2:同⼀系列的库函数⼀般会声明在同⼀个头文件中(比如,与字符串相关的库函数的声明就在头文件string.h中)。使用库函数前,一定要包含对应的头文件(函数要先声明后使用,包含头文件就相当于函数的声明)

2.3:C++中提供的库函数的链接

2.4:库函数对应的头文件链接

3.自定义函数

3.1:实参(实际参数)


#include <stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int r = Add(a, b);
	printf("%d\n", r);
	return 0;
}

调用Add函数时,传递给函数的参数a和b,称为实际参数,简称实参。

3.2:形参(形式参数)

当函数未被调用时,并不会向栈区为函数的形参分配空间。只有当函数被调用时,才会在栈区为形参分配空间,用来存储实参传过来的值。

3.3:实参与形参的关系

在这里插入图片描述
形参只是接收了实参的值,但形参与实参的空间不一样的,形参值的改变并不会影响实参值的改变

4.return语句的几点注意事项

1.当函数的返回值类型是void时,可以不写return语句,或者写return ;表示不返回任何值)

2.return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执行表达式,再返回表达式的结果。

3.return语句执行后,函数就彻底返回,后边的代码不再执行。

4.return返回的值和函数返回类型不⼀致,系统会自动将return返回的值隐式转换为函数的返回类型。(建议将函数的返回值与返回类型保持一致)

int test()
{
	int n = 1;
	if (n == 1)
		return 1.5;
	else
		return -1.5;
}
int main()
{
	int r = test();//test函数返回的是1,而不是1.5
	printf("%d", r);//1
	return 0;
}

5.如果函数中存在if等分支的语句,则要保证每种情况下都有return返回,否则编译器可能会报警告(不是报错误)

在这里插入图片描述

6.C语言中,如果函数不写返回值类型,则编译器会默认为该函数的返回值类型是int,且这种写法是极不推荐的!!!。另外,在C++中,如果函数不写返回值类型,编译器将报错。

在这里插入图片描述

7.当函数写了返回值类型,但没有写return语句,则函数返回的是随机值(这种写法也极不推荐!!!)

double test()
{
	printf("hello\n");
}
int main()
{
	double r = test();
	printf("%lf", r);
	return 0;
}

5.数组做函数参数

5.1:数组传参(要理解透彻)

在这里插入图片描述
结合下面这幅图来理解
在这里插入图片描述

5.2:一维数组传参时,形参若写成数组的形式,数组的大小可以省略不写;二维数组传参时,形参若写成数组的形式,数组的行的大小可以省略不写,但列的大小必须写。

void print_arr(int arr1[][5], int r, int c)
{
	//第一个形参与int *arr1完全等价,本质都是用指针变量arr1来接收数组首元素的地址
	for (int i = 0; i < r; i++)
	{
		for (int j = 0; j < c; j++)
		{
			printf("%d ", arr1[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	print_arr(arr, 3, 5);
	return 0;
}

6.函数的嵌套调用与链式访问

6.1:嵌套调用

6.1.1:何为嵌套调用?

如函数A中调用函数B,函数B中调用函数C

6.1.2:计算某年某⽉有多少天?
#include<stdio.h>
#include<stdbool.h>
bool is_leap_year(int y)//判断年份y是否是闰年
{
	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
		return true;
	else
		return false;
}
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;//闰年:2 月 29 天  ,平年:2 月 28 天
	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;
}

6.2:链式访问

6.2.1:何为链式访问?

将一个函数的返回值作为另外一个函数的参数,像链条一样将多个函数串接起来。

#include<string.h>
#include<stdio.h>
int main()
{
	printf("%zd\n", strlen("abcdef"));//将strlen函数的返回值作为printf的参数
	return 0;
}
6.2.2:printf函数的返回值是什么?

成功打印字符的个数

int main()
{
	int r = printf("%d\n", 112);
	printf("%d\n", r);//4    printf这个打印了112(三个字符)和一个换行符,因此它的返回值是4
	return 0;
}
6.2.3:下面这段有趣的代码的运行结果是什么?
int main()
{
	printf("%d", printf("%d", printf("%d", 43)));
	return 0;
}

在这里插入图片描述

7.函数的定义与声明

7.1:函数的定义与声明与调用之间的关系

a.函数必须先声明后使用。函数声明就是告诉编译器有这个函数的存在(以及这个函数的返回值类型是什么,名字是什么、参数的类型是什么)。
b.函数定义就是函数的实现。
c.如果函数定义写在函数调用之前,就可以直接调用该函数。因为函数定义是一种特殊的函数声明。

7.1.1:单个文件

在单个源文件中,若函数调用写在函数定义之前,进行函数声明时,不需要加extern关键字

#include<stdio.h>
int is_leap_year(int y);//函数声明

int main()
{
	int y = 0;
	scanf("%d", &y);
	int r = is_leap_year(y);
	if (r == 1)
		printf("闰年\n");
	else
		printf("不是闰年\n");
	return 0;
}

//判断⼀年是不是闰年
int is_leap_year(int y)
{
	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
		return 1;
	else
		return 0;
}
7.1.2:多个文件
a.⼀般在企业中写代码时候,代码可能比较多,不会将所有的代码都放在⼀个文件中。往往会根据程序的功能,将代码拆分放在多个文件中。一般情况下,头文件(.h文件)中写函数的声明(还可以类型的定义,如单链表中声明一个结构体类型,用来表示一个结点的结构),源文件(.c文件)中写函数的实现,当要使用该函数时,就只需要包含该头文件。包含自己写的头文件时用" ",包含C语言标准库提供的头文件时用< >

在这里插入图片描述
在这里插入图片描述

b.在源文件(.c文件)中包含头文件的本质是什么?

将头文件中的所有内容复制一份到该源文件中。

8.static(静态) 与extern(与"数据类型与变量"这篇博客中的第4点结合起来看)

8.1:静态区中数据的特点

全局变量、被static修饰的(局部变量、全局变量)都是存放在静态区中的。存放在静态区中的数据,代码在编译阶段就已经为这些数据分配空间了,也就是这些数据说在main函数执行前就已经有了,且这些数据的生命周期与整个工程生命一致。

8.2:static修饰局部变量

a.下面这两段代码的执行结果是什么?

在这里插入图片描述
代码1的执行结果是2 2 2 2 2
每当test函数被调用时,局部变量i就创建了,等调用结束时,i出了作用域就销毁了,等下一次调用test函数时,i又会重新创建。
代码2的执行结果是2 3 4 5 6
局部变量i被static修饰了,因此它是存放在静态区的,i在main函数执行前就已经被创建了,因此调用test函数时,static int i=0;这句代码不会被执行。i的作用域就是test函数的大括号中(并不是整个工程),但它出了作用域也不会被销毁,它的生命周期与整个程序的生命周期一致。每调用一次test函数,i的值都会在原来的基础上加1

b.static修饰局部变量的特点

被static修饰的局部变量,它的存储位置不再是栈区,而是静态区。因此它的生命周期与整个工程的生命周期一致(从main函数开始执行到return 0这段时间),但它的作用域依旧是所在的大括号内部。

c.什么时候使用static修饰局部变量?

未来⼀个变量出了函数后,我们还想保留它的值,等下次进入函数继续使用,就可以使用static修饰。

补充:
int main()
{
	for (int i = 0; i < 5; i++)
	{
		int a = 4;
		a++;
		printf("%d ", a);
	}
	return 0;
}
//这里a创建并销毁了5次,每当打印完a的值后,a就销毁了

8.3:static修饰全局变量

a.全局变量具有外部链接属性。在一个源文件中定义的全局变量,若想在其他源文件中使用,只需要在该源文件中用extern声明就行了。

在这里插入图片描述

b.static修饰全局变量的特点

全局变量被static修饰后,它的外部链接属性就变成了内部链接属性。即使在其他源文件中用extern声明了也不能使用。
在这里插入图片描述

c.什么时候用static修饰全局变量?

如果⼀个全局变量,只想在它所在的源文件内部使用,其他源文件中无法使用,就可以使用static修饰。

8.4:static修饰函数

a. 函数具有外部链接属性。在一个源文件中定义的函数,若想在其他源文件中使用,只需要在该源文件中用extern声明就行了。

在这里插入图片描述

b.static修饰函数的特点

函数被static修饰后,它的外部链接属性就变成了内部链接属性。即使在其他源文件中用extern声明了也不能使用。
在这里插入图片描述

c.什么时候用static修饰函数?

如果⼀个函数,只想在它所在的源文件内部使用,其他源文件中无法使用,就可以使用static修饰。

8.5:extern关键字是用来声明外部文件中的符号的

http://www.dtcms.com/a/112302.html

相关文章:

  • Opencv计算机视觉编程攻略-第九节 描述和匹配兴趣点
  • vue进度条组件
  • Vue3引入ElementPlus
  • SpringCloud第二篇:注册中心Eureka
  • 二叉树 树 - 问题集合
  • 列表与列表项
  • 爬虫案例:使用webpack爬取批量数据
  • 数据库DBA职业规划与技能提升指南
  • Linux | I.MX6ULL 终结者底板原理图讲解完(6)
  • 【Lua】pcall使用详解
  • PCI与PCIe接口的通信架构是主从模式吗?
  • spring IOC 反射 bean生命周期
  • JAVA实战开源项目:在线问卷调查系统(Vue+SpringBoot) 附源码
  • JavaScript 中常见的鼠标事件及应用
  • ASP.NET Core Web API 中 HTTP状态码的分类及对应的返回方法
  • OpenVLA-OFT——微调VLA的三大关键设计:支持动作分块的并行解码、连续动作表示以及L1回归目标
  • 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
  • 使用 SignalR 在 .NET Core 8 最小 API 中构建实时通知
  • 项目实战(16)-GNSS码表
  • springboot集成Kafka
  • 如何在Springboot的Mapper中轻松添加新的SQL语句呀?
  • Eclipse 视图(View)
  • 大模型如何引爆餐饮与电商行业变革
  • 如何在Redis容量限制下保持热点数据
  • Vue3使用富文本编辑器vue-quill 自定义图片上传、文件上传
  • 数据库——MySQL数字函数和子查询
  • 交互式 AI 系统
  • C++ 极简常用内容
  • 电商---part02 项目环境准备
  • 如何根据电池电流计算电池容量