C语言基础——函数(2)

             ʕ • ᴥ • ʔ             

 🎉 🎉

文章目录

前言

一、return语句

二、数组做函数参数

三、嵌套调用和链式访问

3.1 嵌套调用

3.2 链式访问

四、函数声明和定义

4.1 单个文件

4.2 多个文件

总结


前言

大家好啊,继我们上一次讲的函数(1)已经过了两周了,不知道大家掌握的怎么样,由于要期末考试,我断更了两周,希望大家见谅,那么我们接着上一章节来继续说说函数的内容吧。我们这一章节就来看看return语句和数组传参及嵌套调用和链式访问等问题,接下来我们来一起学习本次的内容。


一、return语句

我们在使用函数的过程中,总是使用到return语句,例如

int Add(int a, int b)
{int c = a + b;return c;
}

既然return这么重要,那它到底怎么使用呢,我们来了解了解。

1. return后面可以是一个数值,也可以是一个表达式,但是如果return后面是表达式的话要先计算表达式的内容,在返回结果。

2. return后面可以什么都没有,直接写return,这种写法适合函数返回类型是void(无类型返回)的情况

3. return返回的值和函数返回的类型不一致,系统会自动返回的值转换成函数返回的类型。

4. return执行后,函数就彻底返回,后面的代码不执行。

5. 如果函数中出现了if分支,要确保每个分支都有返回的情况,不然程序会报错。

我来一条一条的为大家解释。

首先是第一条,我们可以从上节课的代码就能知道,return可以直接返回数值,也可以返回一个表达式。

int Add(int a, int b)
{int c = a + b;return c;
}
int Add(int a, int b)
{return a + b;
}

表达式是先通过计算出结果后才返回最终的值的,这很好理解,就不多赘述。

其次是第2条也很好理解,函数本身是不需要任何的返回类型的,那return后面肯定什么也不能加的,可能会有人疑问那这个return加在这个函数里面有什么用,当然是有用的这个就可以和第4点结合起来,它可以直接中断函数而不继续运行下面的代码。这就是这个return的作用。

void Print(int n)
{if (n <= 0){return;}for (int i = 1; i <= n; i++){printf("%d ", i);}
}int main()
{int n = 0;scanf("%d", &n);Print(n);return 0;
}

我们可以来看这个代码,这个代码的目的是如果n>0就把1~n的数字打印出来,我们可以来看这个打印的函数Print就可以看到,如果n<=0就return,我们可以来看看这个return后还会不会继续运行函数下面的代码了。

可以看到,我输入一个正数它很好的打印出来了,那我输入一个负数或者0会怎么样呢?

很显然,它什么都没有输出,这就是return的强大,它比break都强,break是跳出循环,而return是直接跳出函数。

我们现在来看看第3点,其实也很好理解,就是如果return返回的类型和函数要求的返回类型不一样是会转换成函数类型。

char test(char a)
{int b = a;return b;
}int main()
{char a;scanf("%c", &a);int b = sizeof(test(a));printf("%d", b);return 0;
}

我们可以来看看这个代码,我们先输入一个字符,然后写一个函数,这个函数的返回类型是字符型,但是我却返回了一个整型,那我们来看看它到底返回的是字符还是整型吧,我们可以知道字符的sizeof是1,而整型是大于等于2。

可以看到是1,所以返回回来的是字符型。也就是函数要求的返回类型。

最后我们来看看第5点,其实也很简单,你想想,如果一个要求要返回内容的函数却没有返回内容会怎么办,肯定会出现问题啊,可能你十分肯定不会有其他情况发生,但是万一呢,万一发生了呢,可能你会想那再改嘛,但是给了用户后发生这种情况导致程序崩溃了,那是多大的损失啊。所以为了防止这种事情的发生,函数中如果有if,那必须都有返回值,不然程序会报错的。

二、数组做函数参数

我们在使用函数的过程之中,难免会使用到数组做参数,就比如说我们如果想写一个函数,让它把数组里的数据都变成0,那就得把数组传参到函数中,那我们接下来了解了解数组如何传参吧。

我们可以先来写两个关于数组传参的函数,第一个就是把数组里的数据都变成0的函数,第二个则是打印数组的函数。

int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };set_arr();     //把数组里的数据都变成0print_arr();   //打印数组的函数return 0;
}

我们可以先来想想,如果我们要去让数组内的数据都变成0的话,肯定还是要知道数组里的元素个数的,而且我们之前传实参的时候都是在()内输入要传过去的东西的名字的,按道理来讲数组也是这样的,我们之前说过数组的名是[ ]前的,也就是arr,所以说最后就变成了这样。

int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int sz = sizeof(arr) / sizeof(arr[0]); //求元素的个数set_arr(arr, sz);     //把数组里的数据都变成0print_arr(arr, sz);   //打印数组的函数return 0;
}

这就是实参的写法,实参传输过去变成形参啦,那形参该怎么写呢?我们参考上一章节的内容就可以知道其实很简单,唯一困难的地方就是不知道数组该用什么类型来表示。这里我们来复习一下我们前面讲数组是说数组是什么类型的啊,除去我们命名的东东其他的就是它的类型,比如我们这里的arr它的类型是int [ ],那我们的形参是不是 int [ ] arr呢,答案肯定是否定的,其实没有那么复杂,直接就是数组啥样它啥样就行了,数组是int arr[ ],那形参也是int arr[ ];当然,如果你想换个名字,比如说int brr[ ]也可以。所以说最终函数长这样。

void set_arr(int arr[], int sz)
{for (int i = 0; i < sz; i++){arr[i] = 0;}
}void print_arr(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int sz = sizeof(arr) / sizeof(arr[0]); //求元素的个数set_arr(arr, sz);     //把数组里的数据都变成0print_arr(arr, sz);   //打印数组的函数return 0;
}

这就是数组的传参方式,当然,不知这一种,等我们学到指针时还有其他的办法会更实用一点。当然,数组这里还有几个重要的知识点得掌握。

1. 函数的形式参数要和函数的实际参数相匹配。

也就是说实参传了两个参数过去,那形参就一定要用两个参数接收,不能多也不能少。

2. 函数的实参是数组,形参也是可以写成数组的形式的。

3. 形参如果是一维数组,那数组的大小可以省略不写。

也就和我上面的相同,[ ]中没有数组的大小,当然如果写了也无伤大雅。

4. 形参如果是二维数组,行可以省略,但是列不行,就和创建二维数组相同。

5. 数组传参,形参是不会创建新数组的。

也就是说实参的数组和形参的数组是一个数组,而不是和上节课那样只是数据相同,但不是同一个东西,数组就是同一个数组。

6. 形参操作的数组和实参操作的数组是同一个数组。

同上面同理。

三、嵌套调用和链式访问

3.1 嵌套调用

嵌套调用就是函数之间相互调用,就像孔明锁或者鲁班锁,各种不同的结构相互平凑在一起,形成了一个非常稳固的结构。而正是因为函数之间有效的相互调用才形成了相对的的程序。

假如我们要写一个程序,要让它求出某年某月有多少天怎么做呢?我们来看一下。

int main()
{int years = 0;int month = 0;scanf("%d %d", &years, &month);int day = get_month_day(years, month); // 用来求某年某月有多少天的函数printf("%d", day);return 0;
}

这是主函数,我们可以先创建一个函数来解决这个问题,我们来分析一下这个问题,其实很简单,月份基本上是固定的,唯一一个不固定的月份就是二月,闰年二月29天,平年二月28天,所以问题就变成了一个找闰年的问题,我们可以再创建一个函数来判断是不是闰年。

int is_leap_year(int y) //是闰年返回1,不是返回0
{if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0){return 1;}else{return 0;}
}
int get_month_day(int y, int m)
{int arr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };//由于arr的下标是从0开始的,所以说我们可以空一位,让下标0变成0if (is_leap_year(y) == 1 && m == 2){return arr[m] + 1;}else{return arr[m];}
}int main()
{int years = 0;int month = 0;scanf("%d %d", &years, &month);int day = get_month_day(years, month); // 用来求某年某月有多少天的函数printf("%d", day);return 0;
}

我们可以得到以上的函数,这就能很好的满足我们的要求,这就是嵌套调用。

当然还可以用switch,大家可以去试一试,这里就不带大家尝试了。

大家要注意函数不能嵌套定义,就是说在一个函数中在定义一个函数是万分不可的。

3.2 链式访问

链式访问就是值把一个函数的返回值作为一个函数的参数,像链条一样将函数串起来就是链式访问。

就比如我们之前玩过的strlen函数,它的作用是求字符串长度

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

这个代码很容易懂,就是求出ABCDEFG的大小后存储在a中,然后再用printf函数输出出来。

可能有人就在想了,能不能直接把strlen写在printf里面,不用a保存,比如

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

当然可以,这就是一个链式访问,将strlen函数的返回值放在printf的参数之中。

四、函数声明和定义

4.1 单个文件

我们在创建函数的时候一般都是把函数写在主程序的前面,例如

int Add(int a, int b) //函数的定义
{return a + b;
}int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = Add(a, b);//函数的调用printf("%d", c);return 0;
}

我们把上面的函数叫做函数的定义,而下面引用函数的地方叫做函数的调用。但是我们其实也可以把函数写在主函数的下面。

int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = Add(a, b);//函数的调用printf("%d", c);return 0;
}int Add(int a, int b) //函数的定义
{return a + b;
}

这个时候我们运行代码会发现程序报错了。

上面显示说是Add未定义,原因是因为编译器在从上往下编译时发现主程序中有Add这个函数,但是它在前面没有看见过,所以就显示未定义,这个时候我们就可以声明一下。

int Add(int a, int b);//函数的声明int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = Add(a, b);//函数的调用printf("%d", c);return 0;
}int Add(int a, int b) //函数的定义
{return a + b;
}

这就是函数的声明,这样程序就能正常运行了,当然,函数的定义是特殊的函数声明。

4.2 多个文件

其实我们一般在创建函数是都不会在一个文件中创建,一般会分为两个文件

.h(头文件) ---- 函数的声明;

.c(源文件) ---- 函数的定义;

以上就是我们声明函数的地方。

以上就是我们函数定义的地方。

我们在头文件中声明函数,在源文件中定义函数,最后再在我们的主文件中使用函数,这就是多个文件的函数声明和定义。

声明:

定义:

使用:

在使用时要注意要引用我们自己创建的头文件,我们自己的头文件用" "来引用。


总结

以上就是函数的内容啦,希望大家好好吸收和理解下一章节我来说说操作符吧。感谢大家的观看,如果哪里有误,欢迎支持,谢谢大家。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

django学习入门系列之第三点《案例 小米商城二级菜单》

文章目录 样例划分区域搭建骨架logo区域完整代码 小结往期回顾 样例 划分区域 搭建骨架 <!-- 二级菜单部分 --> <div class"sub-header"><div class"container"><div class"logo">1</div><div class"sea…

Python爬虫学习 | Scrapy框架详解

一.Scrapy框架简介 何为框架&#xff0c;就相当于一个封装了很多功能的结构体&#xff0c;它帮我们把主要的结构给搭建好了&#xff0c;我们只需往骨架里添加内容就行。scrapy框架是一个为了爬取网站数据&#xff0c;提取数据的框架&#xff0c;我们熟知爬虫总共有四大部分&am…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十七)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 27节&#xff09; P27《26.Stage模型-UIAbility的启动模式》 本节讲解 UIAbility的启动模式&#xff1a;Stage模型的应用&#x…

排序之插入排序----直接插入排序和希尔排序(1)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 排序之插入排序----直接插入排序和希尔排序(1) 收录于专栏【数据结构初阶】 本专栏旨在分享学习数据结构学习的一点学习笔记&#xff0c;欢迎大家在评论区交流讨…

算法训练营day20--235. 二叉搜索树的最近公共祖先+701.二叉搜索树中的插入操作 +450.删除二叉搜索树中的节点

一、235. 二叉搜索树的最近公共祖先 题目链接&#xff1a;https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/ 文章讲解&#xff1a;https://programmercarl.com/0235.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91…

天马学航——智慧教务系统(移动端)开发日志三

天马学航——智慧教务系统(移动端)开发日志三 日志摘要&#xff1a;更新了学生选课模块、我的课程模块以及退课的功能&#xff0c;优化了后端数据库的缓存 1、学生选课模块 学生选课模块主要实现&#xff0c;学生根据需求进行选课操作&#xff0c;通过后端查询到所有教师的课…

一份简单的海外问卷,改变经济现状

在许多人看来&#xff0c;赚钱似乎总是与资金和技术密切相关。然而&#xff0c;即使没有丰富的资金和高超的技术&#xff0c;仍然有机会赚取可观的收入。 首先&#xff0c;需要明确的是&#xff0c;赚钱并非完全依赖于物质资本和技术能力。在这个充满机遇的时代&#xff0c;选…

深入源码设计!Vue3.js核心API——Computed实现原理

如果您觉得这篇文章有帮助的话&#xff01;给个点赞和评论支持下吧&#xff0c;感谢~ 作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来 书籍&a…

谷歌云(GCP)4门1453元最热门证书限时免费考

谷歌云(GCP)最新活动&#xff0c;完成免费官方课程&#xff0c;送4门最热门考试免费考试券1张(每张价值200刀/1453元)&#xff0c;这4门也包括最近大热的AI/ML考试&#xff0c;非常值得学习和参加&#xff0c;活动7/17截止 谷歌云是全球最火的三大云计算厂商(前两名AWS, Azure…

投票多功能小程序(ThinkPHP+Uniapp+FastAdmin)

&#x1f389;你的决策小助手&#xff01; 支持图文投票、自定义选手报名内容、自定义主题色、礼物功能(高级授权)、弹幕功能(高级授权)、会员发布、支持数据库私有化部署&#xff0c;Uniapp提供全部无加密源码。​ 一、引言&#xff1a;为什么我们需要多功能投票小程序&#…

NSSCTF中的[WUSTCTF 2020]朴实无华、[FSCTF 2023]源码!启动! 、[LitCTF 2023]Flag点击就送! 以及相关知识点

目录 [WUSTCTF 2020]朴实无华 [FSCTF 2023]源码&#xff01;启动! [LitCTF 2023]Flag点击就送&#xff01; 相关知识点 1.intval 绕过 绕过的方式&#xff1a; 2.session伪造攻击 [WUSTCTF 2020]朴实无华 1.进入页面几乎没什么可用的信息&#xff0c;所以想到使用dis…

【c语言】二级指针

1&#xff0c;定义 本质还是从指针的角度去理解&#xff0c;只不过存的指针的值 2&#xff0c;使用方法

Android使用DevRing框架搭建数据库实体类以及使用

一、引用DevRing依赖 //导入DevRing依赖implementation com.ljy.ring:devring:1.1.8创建数据库表的依赖implementation org.greenrobot:greendao:3.2.2 // add libraryimplementation org.greenrobot:greendao-generator:3.0.0 二、修改工程目录下的.idea->gradle.xml文件&…

Golang笔记:使用serial包进行串口通讯

文章目录 目的使用入门总结 目的 串口是非常常用的一种电脑与设备交互的接口。这篇文章将介绍golang中相关功能的使用。 本文使用的包为 &#xff1a;go.bug.st/serial https://pkg.go.dev/go.bug.st/serial https://github.com/bugst/go-serial 另外还有一些常见的包如&…

Springboot民宿信息管理系统-计算机毕业设计源码08818

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对民宿信息管理系统等问题&#xff0c;对民宿…

大模型应用研发基础环境配置(Miniconda、Python、Jupyter Lab、Ollama等)

老牛同学之前使用的MacBook Pro电脑配置有点旧&#xff08;2015 年生产&#xff09;&#xff0c;跑大模型感觉有点吃力&#xff0c;操作起来有点卡顿&#xff0c;因此不得已捡起了尘封了快两年的MateBook Pro电脑&#xff08;老牛同学其实不太喜欢用 Windows 电脑做研发工作&am…

Ant Design Vue Cascader 级联选择 错位问题

当Cascader 多个的时候 对应的下列会错位 如果滚动 他不会跟着元素 而是会跟着屏幕滚动&#xff0c;如下效果 解决方法 在Cascader 标题添加 getPopupContainer 属性监听对应的位置&#xff0c;返回对应的元素 <a-cascader class"smart-width-100 " v-model:…

Sam Altman:从少儿奇才到OpenAI掌舵人

自2022年底发布了ChatGPT以来&#xff0c;OpenAI及其首席执行官Sam Altman迅速成为科技界的焦点人物。Altman的崛起并非偶然&#xff0c;而是长期以来不断追求权力和创新的结果。本文将回顾Altman的成长历程&#xff0c;探索他如何一步步走向OpenAI的顶峰。 童年与教育背景 S…

亚马逊云科技官方活动:一个月拿下助理架构师SAA+云从业者考试认证(送半价折扣券)

为了帮助大家考取AWS SAA和AWS云从业者认证&#xff0c;小李哥争取到了大量考试半价50%折扣券&#xff0c;使用折扣券考试最多可省75刀(545元人民币)。 领取折扣券需要加入云师兄必过班群&#xff0c;在群中免费领取。目前必过班群招募到了超过200名小伙伴&#xff0c;名额有限…

YOLOv8关键点pose训练自己的数据集

这里写自定义目录标题 YOLOv8关键点pose训练自己的数据集一、项目代码下载二、制作自己的关键点pose数据集2.1 标注(非常重要)2.1.1 标注软件2.1.2 标注注意事项a.多类别检测框b.单类别检测框2.2 格式转换(非常重要)2.3 数据集划分三、YOLOv8-pose训练关键点数据集3.1 训练…