小bai笔记:函数和递归(上)

本文详细介绍了C语言中的函数概念,包括函数的定义、库函数的使用、自定义函数的编写、参数传递方式等内容,并通过实例帮助读者深入理解形参与实参的区别。

前言:函数对于代码来说无疑是十分重要的,也是平时使用非常多的语法结构之一。说到函数,可能大家最先想到的是数学上的函数,其实二者没什么必然的联系,虽然同叫函数,但是他俩并不熟哈。言归正传,下面就让我们开始函数的学习。

1函数

        1.1什么是函数:维基百科对于代码中的函数定义为“子程序”。事实也的确如此,在C语言中,函数是相对独立带一段代码块,作用就是实现一种特定的功能。当我们在写代码的时候是不是经常遇到同一段代码多次书写的情况呢,举个简单的例子:我们相求5加6,就写了一个“5 + 6”,下面想求6加8,我们又要写“6 + 8”,这样每次想算两个数的和都要写出来,是不是太麻烦了呢,于是我们就可以写一个加法函数,这样每次需要算加法我们就调用这个函数,就可以简单的实现加法。当然由于加法本身代码很少,所以看上去并不直观,导致好像用函数比直接写还麻烦,事实上我们定义的函数大多数都是很长的,调用函数会比每次现用现写方便的多。

        1.2函数的基本结构:“返回类型 函数名 (参数) {代码块实现}”写一个简单的求和代码,方便大家更好理解函数的基本结构,例如下代码:

//int定义函数类型为整形,即表示最终函数执行结束将返回一个整型,无返回值为void
//Add是函数名,一般都采用一些单词或其缩写,具有一定意义,方便别人读懂,利于后期维护
//int x, int y是参数,用来创建内存空间以接收数据
//{int sum = x+y; return sum;}代码块实现函数功能,return sum;返回整形,对应函数名前的int
int Add(int x, int y)
{
	int sum = x+y;
	return sum;
}

 2库函数

        2.1什么是库函数:相信大家对程序员有所了解的话,一定听说过一个词叫“删库跑路”,这里这个库指得是公司的库,里面放的都是库函数,公司的所有人都可以使用库里面的库函数。而我们C语言呢当然也有一个C库,里面有非常之多的库函数可以供我们使用,大大方便了我们的代码写作。当然这是C语言诞生以来慢慢积累起来的,是前辈所赠,我们在使用的时候当然是不能直接就用的,不能行这个鸡鸣狗盗之事哈。那怎么办呢,于是C语言给我们提供了使用的方法,这里说一下基本用法,在使用库函数的时候,也不用送钱给前辈们,只要跟前辈们打声招呼就行了,用一句话,“#include <头文件>”就可以了,前辈们就会慷慨的给你用了。关于函数声明这一块后面在详细讲,这里就简单讲一下库函数的用法,用那个库函数就引它所在的头文件(库函数非常多,声明在不同分好类的头文件中)。举个例子,我们最常用的输入输出函数,例如下代码:

//include是包含的意思,stdio.h是头文件名字,.h是格式,std是standard,标准的意思,i是input,o是output,是输入输出的意思,所以这个头文件就是“标准输入输出库函数”所在的头文件
#include <stdio.h>

int main()
{    
    int a = 0;
    //标准输出库函数printf
    printf("hehe\n");
    //标准输入库函数scanf
    scanf("%d", &a);
    return 0;
}

3自定义函数

        3.1所谓自定义函数就是我们程序员自己写的函数,因为库函数只提供一些常用的标准函数,目的是统一化标准,使不同人写代码更好的兼容,不然你定义一个输入输出,他定义一个输入输出,那就乱套了。既然是基本的常用函数,那么肯定使无法满足我们所有的需求的,所以定义函数也是程序员存重要工作之一。例如开头的加法函数,就是一个自定义函数

4函数参数

        4.1函数的参数有两种,实参跟形参。所谓实参,就是实实在在的参数,一般在调用函数时传递给函数的是实参,而创建函数定义的,用来接收实参的就是形参。

        4.2当然参数并不一定是一个数,认为参数就是一个数这种想法是错误的。事实上,只要是确定的一个值,都可以作为实参传递给函数,甚至可以用函数做函数的参数,表达式做函数的参数,指针做函数的参数,只要传递时是一个固定的值,就可以在调用函数时作为实参传给函数。

        4.3形参可以看作是实参的一份临时拷贝,当调用函数时,形参向内存申请空间,存储的就是实参的值。这点很重要,一定要理解形参和实参的关系。为了帮助大家更好的理解形参和实参,举个例子,写一个交换a和b的值的函数,例如下代码:

void Swap(int x, int y)
{
	int temp;
	temp = x;
	x = y;
	y = temp;
}

int main()
{
	int a = 2;
	int b = 5;
	Swap(a, b);
	printf("a = %d b = %d\n", a, b);
	return 0;
}

 运行结果图:然而我们发现,并没有被交换。说明我们定义的函数没有到达我们的目的,一般这个时候我们先来检查逻辑,然而我们发现逻辑似乎并没有问题。事实上,我们要注意形参的实质,形参可以看作是实参的一份临时拷贝,他向内存申请了一块空间存储的时跟实参a,b一样的值,也就是说形参x,y在内存中有自己的独立地址,跟a,b互补影响,我们在函数中操作x,y对于函数外的a,b没有任何影响。形参x,y随着函数调用而产生,函数执行完自动销毁,所以最终输出a,b是没有交换的,如果输出x,y则编译报错,输出时语句执行时x,y已经销毁。

 当然有的小伙伴就想到了,我直接在函数里输出不就行了吗,例如下代码:

void Swap(int x, int y)
{
	int temp;
	temp = x;
	x = y;
	y = temp;
	printf("a = %d b = %d\n", x, y);
}

int main()
{
	int a = 2;
	int b = 5;
	Swap(a, b);
	return 0;
}

 运行结果如下:看上去似乎我们的成了任务,但是这其实并不是我们想要的,或者说这不是你的Boss想要的。函数作为一个具有独立功能的代码块,我们写的这个函数是给两个实参,然后交换他们的值,而不应该有这句输出函数,实际上我们并不是想输出结果,这里写输出语句只是为了检验成果,这是其一,函数功能不在独立。其二,我们Swap函数想实现的其实是交换两个实参的值,而上面这种写法颇具一种掩耳盗铃的意思,事实上内存上的a和b并没有被改变,a还是2,b也还是5,我们只不过耍了点小聪明,让输出结果看上去成功了,实际上是失败的。这里非常重要,一定要好好理解透彻,有不懂的一定要评论区交流或者直接问我或者查阅资料,一定一定要弄懂。再就是关于其一在啰嗦一句,我们写函数的时候,一定要注意功能的独立和单一,比如加法函数就算“加法”返回“和”的值,不要再函数内在输出一句“sum = ***”,这就破坏了函数功能的单一性,即使你真的想输出,那就在主函数中创建一个变量接收加法函数返回值在输出这个变量,一定要保证函数功能的独立单一性,该干嘛就干嘛。这样做的好处是方便使用,因为大家如果以后上了班,一个项目显然不可能是你一个人在写,你写的函数可能不只你自己用,很可能放到公司库里面去,大家都会用到,比如别人用你的加法函数,他只想要一个结果就好了,他只是想求两个数的和,然后用作下一步计算,结果你写的函数是算完了就输出和是多少而不是返回一个值,那别人显然是不可能用你的代码的,换句话说,你那个样子写代码是没有公司敢要你的。一定要注意函数的独立单一性,第n次强调,非常非常重要。好了,言归正传,那么怎么来实现我们的Swap函数呢?

         4.4传参:函数的参数传递其实有两种,一种是我之前写这种,叫做传值传参,另一种就是接下来要讲的传址传参。所谓传址传参就是调用函数时把地址作为实参传递过去,函数中就可以接引用直接通过地址找到操作数进行操作,存放地址用的时指针变量。关于数据结构和操作符后面会给大家出一期讲解,不懂得可以到时候在细学,现在简单的知道我们内存存放东西都是有地址的,如同我们日常的地址,知道地址就可以找到人一样,知道计算机内存的地址也能找到存储的数据。而指针变量是专门存放地址的一类变量。下面我们用传址传参来实现Swap函数,例如下代码:

//无返回值函数用void定义,int*表示int型的指针变量,即存放int型的变量的地址
void Swap(int* pa, int* pb)
{
	int temp;
    //操作符“*”表示解引用操作符,pa,pb是指针变量,里面存放的是a,b的地址,通过解引用操作符,就可以通过地址找到a,b的值,并进行操作
	temp = *pa;
	*pa = *pb;
	*pb = temp;
}

int main()
{
	int a = 2;
	int b = 5;
    //&是取地址操作符,作用是取地址,即把a,b的地址作为实参传参
	Swap(&a, &b);
	printf("a = %d b = %d\n", a, b);
	return 0;
}

运行结果:

 

 5函数调用

        5.1调用格式:“函数名(参数);”

6函数的嵌套调用和链式访问(比较好理解,简单举两个例子):

        6.1嵌套调用:函数中包含函数,例如下代码:

void Printf1()
{
	printf("哈哈!\n");
}

void Three()
{
	for (int i=0; i<3; i++)
	{
		Printf1();
	}

}

int main()
{
	Three();
	return 0;
}

运行结果:

         6.2链式访问:函数作为函数参数,例如下代码:

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

运行结果:这个结果大家可能比较疑惑,简单给大家讲解一下printf这个函数,既然是用它做参数,我们就得知道他的返回值,不知道的我们就需要查阅,这里给大家附一个网站:

cplusplus.com - The C++ Resources Networkhttp://cplusplus.com/我们查一下printf这个函数: 

 Return Value显然就是返回值啦,这里给大家翻译一下:

        意思就是函数没有错误时,返回值就是打印出的字符数。最里面的printf最先执行,屏幕打印43,返回2作为参数,第二个printf在屏幕打印2,返回值时1作为最外面的printf的参数,在屏幕打印1。

7函数的声明和定义

        7.1我们以后进入公司工作,一个大项目肯定都是由很多人同时在做的,如果大家都在一个cpp文件来写代码显然是不现实的。所以就用到了我们的函数的声明,其实跟库函数非常的类似。具体怎么做呢?就是每个人写函数自己建一个cpp文件来写,然后建一个头文件,即.h文件,在同文件中声明函数,这样项目的主代码中用到谁写的函数,就在开头(重点,一定要在开头)引用一下头文件打个招呼就好了。

        7.2具体格式:cpp文件中写函数代码,.h头文件声明,格式是“定义类型 函数名 (参数)”如图(这是我写的一个简易计算器的头文件)(参数可以不写具体形参,写明类型就可以,例如void Add(flaot*, float )):

         7.3主函数中使用引用头文件即可,格式与引用库函数很像,只是把<>换成了"",如图:

8小结

        8.1这期就到这里啦,讲解了一下函数的基础知识,重点就是形参和实参的理解,下一期将着重讲解递归。

        8.2如果觉得对你有帮助欢迎点赞转发评论区交流,关注小白阿g,让小白不再白学,亲爱的小伙伴们下期见。

欧姆龙FINS(工厂集成网络系统)协议是专为该公司自动化设备间数据交互而设计的网络通信标准。该协议构建于TCP/IP基础之上,允许用户借助常规网络接口执行远程监控、程序编写及信息传输任务。本文档所附的“欧ronFins.zip”压缩包提供了基于C与C++语言开发的FINS协议实现代码库,旨在协助开发人员便捷地建立与欧姆龙可编程逻辑控制器的通信连接。 FINS协议的消息框架由指令头部、地址字段、操作代码及数据区段构成。指令头部用于声明消息类别与长度信息;地址字段明确目标设备所处的网络位置与节点标识;操作代码定义了具体的通信行为,例如数据读取、写入或控制器指令执行;数据区段则承载实际交互的信息内容。 在采用C或C++语言实施FINS协议时,需重点关注以下技术环节: 1. **网络参数设置**:建立与欧姆龙可编程逻辑控制器的通信前,必须获取控制器的网络地址、子网划分参数及路由网关地址,这些配置信息通常记载于设备技术手册或系统设置界面。 2. **通信链路建立**:通过套接字编程技术创建TCP连接至控制器。该过程涉及初始化套接字实例、绑定本地通信端口,并向控制器网络地址发起连接请求。 3. **协议报文构建**:依据操作代码与目标功能构造符合规范的FINS协议数据单元。例如执行输入寄存器读取操作时,需准确配置对应的操作代码与存储器地址参数。 4. **数据格式转换**:协议通信过程中需进行二进制数据的编码与解码处理,包括将控制器的位状态信息或数值参数转换为字节序列进行传输,并在接收端执行逆向解析。 5. **异常状况处理**:完善应对通信过程中可能出现的各类异常情况,包括连接建立失败、响应超时及错误状态码返回等问题的处理机制。 6. **数据传输管理**:运用数据发送与接收函数完成信息交换。需注意FINS协议可能涉及数据包的分割传输与重组机制,因单个协议报文可能被拆分为多个TCP数据段进行传送。 7. **响应信息解析**:接收到控制器返回的数据后,需对FINS响应报文进行结构化解析,以确认操作执行状态并提取有效返回数据。 在代码资源包中,通常包含以下组成部分:展示连接建立与数据读写操作的示范程序;实现协议报文构建、传输接收及解析功能的源代码文件;说明库函数调用方式与接口规范的指导文档;用于验证功能完整性的测试案例。开发人员可通过研究这些材料掌握如何将FINS协议集成至实际项目中,从而实现与欧姆龙可编程逻辑控制器的高效可靠通信。在工程实践中,还需综合考虑网络环境稳定性、通信速率优化及故障恢复机制等要素,以确保整个控制系统的持续可靠运行。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值