庖丁解牛函数知识---C语言《2》

news2024/11/18 6:59:53

目录

前言:

1.嵌套调用函数

2.链式访问

3.函数的声明与定义

4.*递归

5.递归与非递归


❤博主CSDN:啊苏要学习

  ▶专栏分类:C语言◀

  C语言的学习,是为我们今后学习其它语言打好基础,C生万物!

  开始我们的C语言之旅吧!✈


前言:

  在第一篇的基础上,我们接着学习函数相关的知识。虽然都是基础知识,但干货满满,读来没有新的知识收获,也有复习的奇效

1.嵌套调用函数

  在C语言中,调用函数是非常常见的。我们需要使用函数来解决问题,自然就需要把函数给调出来使用。那么什么是嵌套调用呢?我们看下面的代码:

#include <stdio.h>


void put_word(int n)
{
    if (11 == n)
        printf("I miss you!\n");
    if (13 == n)
        printf("I want to say\n");
}
void put_line()
{
    int a = 0;
    int i = 0;
    printf("Hello long time no see!\n");
    for (i = 0; i < 2; i++)
    {
        if (i != 1)
        {
            printf("你可以输入两次\n");
        }
        printf("请输入你要听的字符数(13,11)>:");
        scanf("%d", &a);
        put_word(a);
    }

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

  这段代码的逻辑是:先在main函数里调用put_line函数;进入到put_line函数里面再调用了put_word函数;这里是多层调用,A调用B,B调用C来完成"我想你"这段有趣的输出这种就是函数的嵌套调用

  函数的嵌套调用是必要的,比如在生成汽车的时候,原材料从哪里来,各种原材料加工厂是原材料变成相应的部件,最后组装在一起变成汽车在计算机中,每个函数就是一个部件,最后有机组合(嵌套调用)在一起,完成程序任务

  补充:

  相信大家看完这段代码后,印象会更深刻一点~

2.链式访问

  链式访问是将函数的返回值作为一个函数的参数使用

#include <stdio.h>
#include <string.h>

int main()
{
    int len = strlen("abcdef");
    printf("%d\n", len);
    printf("%d\n", strlen("abcdef"));
    return 0;
}

  printf函数参数为strlen("abcdef")利用的就是函数的链式访问,strlen返回字符串的长度,这个长度作为printf函数的参数被打印出来

  它的效果和使用整型len接收strlen返回的长度,并打印len是一样的

  我们接下来看这样一段代码,感受函数的链式调用:

#include <stdio.h>

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

  这段代码将打印什么呢?首先最外层的printf要打印一个整型值,它要看里层printf函数的返回值是多少; 里层函数要打印一个整型值,它要看最里层printf函数的返回值是多少这个时候,从最外层的printf函数打印,层层往里像一条链一样串起来

  现在已经分析到最里层的printf函数了,它打印了43这个整型,但我们不知道printf函数打印完后,返回什么东西,这时候我们得上网站查一查:cplusplus.com

  具体的使用方法可以快速阅读一下上一篇函数知识讲解如何学习库函数:链接

  得知printf函数的返回值是成功读取到字符的个数那么最里层printf函数成功读取到43这两个字符,返回值是2;上面的代码就变成了printf("%d", printf("%d", 2));这样子了接着就是里层打印2,成功读取的字符个数是1,返回值为1,变成printf("%d", 1);

  最终在屏幕上显示的就是:

3.函数的声明与定义

  函数的使用必须遵循先声明后使用的原则

#include <stdio.h>

int Add(int, int);//声明Add函数
int main()
{
    int a = 10;
    int b = 20;
    printf("%d\n", Add(a, b));
    return 0;
}

int Add(int x, int y)//定义函数
{
    return x + y;
}

  声明函数的时候,需要指出它的返回类型、函数名、函数的参数类型,由于声明是一条语句,不要漏了最后的分号。  

  补充:函数声明参数的时候,可以只写类型,而不用写名字。我们不必写int Add(int x, int y);

  由于程序的执行流程是从上往下执行的,程序入口是main函数,所以将定义放在函数使用之前,就可以不用声明

#include <stdio.h>

int Add(int x, int y)//定义函数
{
    return x + y;
}

int main()
{
    int a = 10;
    int b = 20;
    printf("%d\n", Add(a, b));//已经知道Add是什么样的函数了
    return 0;
}

  这是一种特殊的声明,定义声明。主旨思想就是:编译器需要知道你使用的函数是什么,要么定义在我使用之前,要么你告诉我这个函数是什么

4.*递归

  函数自己调用自己叫做递归;递归往往能将一个大量重复的计算用简洁少量的代码写出来,递归的本质是大事化小。我们先来看一个代码:

#include <stdio.h>

//打印12345的每一位数
void print(int n)
{
    if(n > 9)
    {
        print(n/10);//打印1234的每一位数
    }
    printf("%d ", n%10);//打印5
    
}

//打印1234的每一位数
//void printf(int n)
//{
//   if(n > 9)
//    {
//        print(n/10);//打印123的每一位数
//    }
//    printf("%d ", n%10);//打印4
//}
//...
//...
//打印1的每一位数
//void printf(int n)
//{
//      if(n > 9)
//      {
//          print(n/10);
//      }
//      printf("%d ", n%10);//1
//}

int main()
{
    int n = 0;
    scanf("%d", &n);//12345
    //将n的每一位打印出来
    print(n);
    return 0;
}

  想求数字12345的每一位,可以使用取模取商交替使用的方法求12345%10 = 5;得到数字5。12345/10得到数字1234;再将1234%10 = 4;得到数字4。1234/10得到数字123........。  

  打印12345的每一位数,我们定义一个print函数用来求之。利用大事化小的本质,可以这样思考:使用print函数打印1234的每一位+打印数字5,再将(打印数字1234的每一位)分解成,打印123每一位+打印数字4.......

  这个比较难理解,再过一会下面有图解,保证清晰易懂~

  从这个思考里面我们可以得出:每次打印最后一位是需要打印数字每一位的最后一位,也就是说当我需要打印数字12345的每一位的时候,我需要打印5,然后在打印数字1234的每一位的时候,我需要打印4以此类推,直到当我在打印数字1的时候,我把最后一位1打印出来,已经没有数字了,程序停止

  注意的要点是:递归需要有限制,没有限制条件或限制条件不恰当都会导致栈溢出

  在调用函数的时候,函数需要在栈上开辟空间,这个过程叫做压栈,如果递归一直持续下去没有完结,栈上的空间都被占满了,没有栈空间程序就自动挂掉,并给警告说栈溢出

  所以使用递归的时候,有两个注意点:

  • 进行递归是有限制条件的,不是可以任何情况都可以递归下去
  • 每进行一次递归调用,都会使递归条件越来越接近结束条件

  在求数字的每一位的时候,进行递归的条件是大于9,也就是要有两位数才进行递归,如果只有一位数,那直接取余打印出来就OK了。每次递归n的值都会少一位,所以这个递归不会出现很大的问题。最重要的一点来了:用画图法来解释刚刚这道代码题,保证能理解透彻。

  一层一层往下递推下去,限制条件限制继续往下递归的时候,开始往回退,一层一层处理,结束

5.递归与非递归

  一般能用递归解决的问题,都可以使用循环解决,因为递归实际上也相当于是在重复做一件事,只不过递归不像循环一样一点都不变,但仍可以使用循环代替。是使用循环还是递归呢?我们需要结合具体情况。

  求斐波那契数列的第n的数:

#include <stdio.h>

//递归实现
int Fib(int n)
{
    if(n <= 2)
        return 1;
    else
        return Fib(n-2)+Fib(n-1);
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    int ret = Fib(n);
    printf("%d\n", ret);
}

  斐波那契数列的规律是:1 1 2 3 5 8 13 21 34 55.......、从第三各个数开始,每个数都是前两个数的和递归的实现思路是:如果求的是第一,第二个斐波那契数列,就返回1;如果不是就返回求n-1和n-2的斐波那契数列值这样一直递归求下去直到n<=2时到达限制条件,不再递归下去了,开始回溯

  假如我们求的是第五十个斐波那契数列,那么由代码可知,我们会求第48斐波那契数列值和第49斐波那契数列值;48再求46和47的,49在求47和48的这样每次递归下去,求的数值都翻一倍,重复计算很多,效率非常低下。我们可以用一个计数器,看看求40的斐波那契额数列值时,Fib(3)被重复计算了多少次!

  被重复计算了3千9百多万次!!! 这时候用递归来求是不可以取的。我们看循环求解斐波那契额数列

#include <stdio.h>


int Fib(int n)
{
    int a = 1;
    int b = 1;
    int c = 1;
    while (n >= 3)
    {
        c = a + b;
        a = b;
        b = c;
        n--;
    }
    return c;
}

int main()
{
    int n = 0;
    scanf("%d", &n);
    int ret = Fib(n);
    printf("%d\n", ret);
    return 0;
}

   循环求解斐波那契数列就是,1 1 2 3 5 8.....、a代表Fib(n-2)、b代表Fib(n-1),每次循环都把Fib(n-2)和Fib(n-1)的和赋给cFib(n),然后整体将a、b整体向右移当n=3时,这个循环操作一次,n=4时,循环操作两次,也就是两次将a、b的和赋值给c,符合要求斐波那契额数列的求法

  这个算法可以很快的算出n = 50时的斐波那契数列值。这时我们会选择用循环解决这个问题。

  总结:什么时候使用递归呢?如果递归的实现比较简单,而且不需要耗费太多时间,我们就可以选择递归。即使递归写起来比较方便,但耗时太久了,我们反而会选择,代码篇幅较长的循环来解决

  文已至此,函数的内容就讲完啦~,感谢观看,咱们下篇见。


结语:希望读者读完有所收获!在学C的路上,祝福我们能越来越C!✔

  读者对本文不理解的地方,或是发现文章在内容上有误等,请在下方评论区留言告诉博主哟~,也可以对博主提出一些文章改进的建议,感激不尽!最后的最后!

  ❤求点赞,求关注,你的点赞是我更新的动力,一起努力进步吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C6678学习-GPIO

文章目录 1、简介2、框图3、寄存器4、地址 1、简介 C6678中共有16个GPIO&#xff0c;GPIO0~GPIO15。这些引脚的功能如下 ​ 通用输入输出管脚​ 中断&EDMA事件管脚 2、框图 1、GPIO作为通用输入输出时&#xff0c;用到的寄存器为DIR、SET_DATA、OUT_DATA、CLR_DATA、IN_…

AI奇点已至,是黎明前的黑暗,还是黑夜前的黄昏

2022年11月&#xff0c;OPEN AI公司推出了ChatGPT 3模型&#xff0c;瞬间引爆全球话题&#xff0c;所有业内人士都在感叹他的强大&#xff0c;比尔盖茨也曾经评价道&#xff0c;ChatGPT将会改变世界 &#xff0c;是一个相当于PC和互联网的革命性产品。 作为信息行业人&#xff…

网络请求与远程资源

网络请求与远程资源 网络分层 一、OSI七层模型、TCP/IP概念层模型 区别&#xff1a;OSI模型注重通信协议必要的功能是什么&#xff0c;TCP/IP模型更强调在计算机上实现协议应该开发哪种程序。 二、应用层的网络协议 FTP&#xff1a;文本传输协议SMTP&#xff1a;简单邮件传输协…

简单理解什么是序列化

为什么要序列化 序列化的目的就是为了对象可以在网络层进行传输&#xff0c; 比如通过后端传给前端数据。 什么是序列化 我们以Java为例。 序列化就是把对象转化为可传输的字节序列过程&#xff0c;这个字节序列可以是字符串&#xff0c;比如JSON格式的字符串&#xff0c;把…

基于海洋捕食者算法的极限学习机(ELM)回归预测-附代码

基于海洋捕食者算法的极限学习机(ELM)回归预测 文章目录 基于海洋捕食者算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于海洋捕食者算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用海洋捕食者算法对极限学习…

一种结合白平衡统计信息和曝光信息的软光敏算法专利学习

背景技术 随着科技的发展&#xff0c;对视频监控设备提出了越来越高的要求。大部分视频监控设备 都需要能够全天候的监控。ICR的中文名称为双滤光片切换器&#xff0c;是用于让滤光片白天切换到红外截止滤光片和晚上切换到全光谱滤光片的监控设备配件。白天的时候&#xff0c…

2023年5月3日 单调栈及其应用

文章目录 单调栈的应用[830. 单调栈 - AcWing题库](https://www.acwing.com/problem/content/description/832/)[P5788 【模板】单调栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)](https://www.luogu.com.cn/problem/P5788)[84. 柱状图中最大的矩形 - 力扣&#xff08;Lee…

chatGPT的翻译能力如何-GPT批量翻译软件

ChatGPT翻译软件 如果您正在为翻译工作而烦恼&#xff0c;或者需要面对语种广泛的国际化业务&#xff0c;那么ChatGPT翻译软件是您的不二之选。 ChatGPT翻译软件基于自然语言处理技术&#xff0c;利用先进的机器学习算法和深度神经网络模型&#xff0c;能够快速、高效地进行多…

将Egg项目部署到阿里云服务器

目录 1、连接阿里云服务器&#xff0c;上传文件 2、在阿里云服务器上安装Nodejs 3、下载项目依赖 4、安装 egg-scripts 模块 5、启动项目 6、阿里云服务器开启7001端口 1、连接阿里云服务器&#xff0c;上传文件 推荐使用FileZilla Client工具连接云服务器&#xff0c;可…

基于蝴蝶算法的极限学习机(ELM)回归预测-附代码

基于蝴蝶算法的极限学习机(ELM)回归预测 文章目录 基于蝴蝶算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于蝴蝶算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用蝴蝶算法对极限学习机进行优化&#xff0c;并…

LVS+Keepalived 高可用群集部署

一、LVSKeepalived 高可用群集 在这个高度信息化的 IT 时代&#xff0c;企业的生产系统、业务运营、销售和支持&#xff0c;以及日常管理等环节越来越依赖于计算机信息和服务&#xff0c;对高可用&#xff08;HA&#xff09;技术的应用需求不断提高&#xff0c;以便提供持续的…

[Git] Git零基础?带你快速入门,示例练习上手

&#x1f61a;一个不甘平凡的普通人&#xff0c;致力于为Golang社区和算法学习做出贡献&#xff0c;期待您的关注和认可&#xff0c;陪您一起学习打卡&#xff01;&#xff01;&#xff01;&#x1f618;&#x1f618;&#x1f618; &#x1f917;专栏&#xff1a;算法学习 &am…

STL--list

一、list介绍 列表是序列容器&#xff0c;允许在序列内的任何位置执行恒定时间插入和擦除操作&#xff0c;以及双向迭代 列表容器作为双向链表实现;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个和后一个元素 它们与forward_list非常…

3.rabbitMQ之发布确认高级和整合springboot(重要)找了很多博客整理出来的

1.极端情况下 rabbitMQ需要重启,导致消息投递失败(生产者发消息全部丢失)(交换机或者队列出问题) 生产者需要把数据放到缓存,用定时任务重新发送 解决方法: 0.必须配置文件写 spring.rabbitmq.publisher-confirm-typecorrelatedspring.rabbitmq.publisher-returnstruecorrelati…

appuploader 入门使用

回想一下我们发布 iOS 应用&#xff0c;不仅步骤繁琐&#xff0c;非常耗时。一旦其中一步失误了&#xff0c;又得重新来。作为一名优秀的工程师不应该让这些重复的工作在浪费我们的人生。在软件工程里面&#xff0c;我们一直都推崇把重复、流程化的工作交给程序完成。这次的文章…

【shell脚本】for循环语句

循环语句与函数 一、循环与遍历1.1循环1.2遍历1.3循环与遍历 二、for循环2.1for循环的基本格式2.2for循环小实验2.3双层for循环实验 三、while循环3.1 while格式 四、跳出循环4.1continue跳出循环实验4.2break跳出循环实验 一、循环与遍历 1.1循环 循环 (Loop) 是计算机编程中…

不会前端,怎么快速打造属于自己的个人博客?

个人博客 简介提前准备 一、初始化vuepress项目二、页面配置首页配置顶部配置顶部导航栏路由配置侧边导航栏配置 三、打包部署四、数据统计插槽自定义插槽配置整体结构页面效果 项目地址 简介 主要教大家如何快速搞一个属于自己的博客网站&#xff0c;特别是一些不怎么会前端的…

【C++】——类与对象(上)

文章目录 1. 前言2. 面向过程和面向对象3. 类的引入4. 类的定义4.1 类的俩种定义方式 5. 类的访问限定符及封装5.1 类的访问限定符5.2 封装 6. 类的作用域7. 类的实例化8. 类对象的存储方式9. this指针9.1 this指针特性 10. 结尾 1. 前言 今天我们来学习C初期最重要的知识点&a…

用于无线传感器网络路由的改进leach协议(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 当前&#xff0c;无线传感器由于技术的发展得到更加广泛的应用&#xff0c;针对无线传感器网络&#xff08;WSN&#xff09;的…

linux重装mmsegmentation

前言 换了个电脑&#xff0c;就想着把之前的mmsegmentation-V0.26.0代码放到新环境&#xff0c;结果踩了不少坑~ 过程 官方步骤 0 安装miniconda 1 创建conda 环境 最开始用的是python3.10&#xff0c;后来发现版本太高不是一件好事&#xff0c;所以装的python3.8 2 安装…