C语言的底层逻辑剖析函数篇(其二),0基础搞定函数,初识函数递归,超详解

C语言的底层逻辑剖析函数篇(其二),0基础搞定函数,初识函数递归,超详解

开篇语

本期内容较为硬核,也较为难理解,温馨提醒:对于函数篇二内容可能到后面会介绍一些你可能压根就没听到过的一些东西,例如模块化开发,静态库,和函数递归的思想和如何使用递归等等,由于我们是第一次接触,可能有些难以理解,希望大家一定不要气馁或者什么负面情绪,抓住重点多多复习几遍,一定可以有所收获。

函数的调用(嵌套调用和链式访问)

我们现在已经初步认识到C语言编程其实就是一个个的函数组合而成,那么对于函数的使用是我们必须要掌握的重点知识,在函数篇其一中我们已经区别了函数调用的传值调用和传址调用,这里我们还有两种调用方式来重点强调一下。

1.嵌套调用

对于函数的嵌套调用,其实大家已经不算陌生了,我们只是将函数之间的相互调用起了一个嵌套调用的名字,我们来举例来说明一下,看以下代码:

void new_line()
{
	printf("hehe\n");
}
void three_line()
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		new_line();
	}
}
int main()
{
	three_line();
	return 0;
}

可以看到我们仿佛是在套娃一样,将一个函数在另一个函数中调用,这就是函数的嵌套调用,另外还有一个值得注意的是函数只能嵌套调用但是绝对不能嵌套定义,就是不能将一个函数定义在另外一个函数内部,这样的代码是绝对错误的,一定要注意!!

2.函数的链式访问

链式访问,顾名思义就像一条链一样对函数进行使用,标准的定义的简单来说就是将函数的返回值作为另一个函数的参数来使用。我们来举个例子:

#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 sum = Add(a, b);
	printf("sum=%d\n",sum);
	return 0;
}

在这段代码中在主函数中一句

int sum=Add(a,b);

我们重点要注意的就是这个地方,我们再来读一遍链式访问的定义将函数的返回值作为另一个函数的参数来使用,有没有一点感觉,我们这里就是将Add的返回值作为了一个参数在主函数中进行了使用,这就是一个链式访问的简单示例,来帮助大家理解,接下来我们再来看一个非常经典的链式访问,

#include<stdio.h>

int main()
{
	printf("%d", printf("%d", printf("%d", 43)));

	return 0;
}

请问这个代码的输出结果是什么?咋一看可能有点懵,但是我们仔细来分析,我们说printf也是一个函数,它也是有返回值的,那么它的返回值是多少呢,不知道你是否还记得在函数篇一中我们提到的网站,当我们不会一些东西是不是应该动手去查一下呢?如果忘了请回传送门复习C语言的底层逻辑剖析函数篇其一,这里我就不再放printf的文档资料了,我直接告诉大家printf返回值就是打印出的元素个数,那么这时候我们再来看此代码运行结果应该是什么,我们来看
在这里插入图片描述
你做对了吗?一定要静下心来仔细分析。

函数的声明和定义

有些教材中写出的代码可能跟我们平时写出的代码长的不太一样,例如:
在这里插入图片描述

我们来看一下区别可能你会发现有些教材将函数的主体写到了我们使用的后面,而由于编译器是从上向下扫描的,如果前面没有声明就会报警告,我们来看右图,前面的int Add其实就是声明,后面的函数主体就是定义,可能你会疑惑好好的函数为什么非要分开写呢,其实教材上这样写只是告诉你函数的声明和定义就是长这个样子,实际上函数的声明和定义不是这样用的;接下来我们就好好的聊一下:

函数声明和定义分开写的两大好处

函数怎么分开写,声明和定义的用途

其实一个函数的实现,我们正常都是写在一个文件里面,但其实以后我们最好都会把函数单独写在一个文件里头,使用的时候用头文件来声明,什么意思呢?我们来看下面:
假设还是上面那个求和函数,
在这里插入图片描述
我又创建了两个文件,一个add.c和一个add.h,我把我的函数定义部分写到add.c中,把函数声明写到add.h中,然后在我的test.c中来使用,使用方式如下:

#include<stdio.h>

#include"add.h"
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int sum = Add(a, b);
	printf("sum=%d\n", sum);
	return 0;
}

用#include来包含一下我的头文件add.h就可以正常使用这个函数了,那么肯定你要有疑问了,一个代码好好的,你为什么闲的没事干把它拆开呢?别着急,我们就来好好聊一下这样写的好处。

初步认识了解模块化开发和静态库

第一大好处,
假设你在公司当一个项目经理,公司要求你和你的团队(假设你要把任务分给4个程序员)完成一个比较大的项目,你会怎么来分配任务,你会怎么分配呢?这时候4个人总不能都在一个文件里面写代码吧,这时候就需要将整个项目分成一个个模块来分配给各个人,上面我们的add.c和add.h其实就是一个模块,
在这里插入图片描述
当我们把任务分给4个人的时候,他们就可以自己开发自己的模块,最后我们只需要将各个模块放到一个项目里面就完成了。
第二大好处
假设你写的这个函数非常有价值,比如一个非常好的游戏引擎,一个游戏公司向你买这一个游戏引擎,你能把源码卖掉吗?我们应该今年卖给他明天还要收费对吧,你花钱用我的引擎,代码的维护我来负责。应该是这样吧,那么我们应该怎么不让他看到我的源代码又可以让他们使用呢?我们往下看:
在这里插入图片描述
我将我的函数和头文件放到一个项目里面,这时候要注意了;
在这里插入图片描述
我把我的项目属性改为静态库,点击应用,然后去编译,
在这里插入图片描述
可以看到我们在这个路径底下生成了一个.lib的文件,我们找到这个文件,这时候用记事本打开:
在这里插入图片描述
发现了吗?打开查看全是一堆乱码,这时候你也看不懂了,我也看不懂了,我就可以把这个文件和我的add.h文件卖出去,那么问题又来了,如果你是买家,这个东西我应该怎么用呢?
我们接着来看:
当我先把这个文件买过来放到项目里面,使用的时候我们需要一步操作叫做哦导入静态库,
在这里插入图片描述

//导入静态库
#pragma comment(lib,"add_11_2.lib")

#include<stdio.h>

#include"add.h"
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int sum = Add(a, b);
	printf("sum=%d\n", sum);
	return 0;
}

这时候我们就可以很好的使用了,这时候站在买家的角度就是只有这样的一个.lib文件和一个.h的头文件,他只能看到头文件函数名,函数返回类型,函数返回参数,但是压根不知道函数内部是怎样实现的,这样就达成了我们的目的。今天我们不讨论什么是静态库,什么是动态库,重点是体会到我们为什么要将函数声明和定义分开写,什么分到另外一个文件中。好了关于这点我们就讨论这么多吧。

函数递归

关于函数递归本来是打算写的,但是考虑到篇幅已经不短了,并且递归和迭代也是极为重要的部分,并且是比较难理解的部分,我们将下一期单独重点来学习。那么今天这期就先结束了。

最后一句鸡汤:任何间歇性的努力和蒙混过日子,都是对之前努力的清零,小伙伴们要加油啊!

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝不过海呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值