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();     //把数组里的数据都变成0
	print_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);     //把数组里的数据都变成0
	print_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);     //把数组里的数据都变成0
	print_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变成0
	if (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(源文件) ---- 函数的定义;

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

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

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

声明:

定义:

使用:

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


总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入测评:ONLYOFFICE 8.1 桌面编辑器究竟有多强大?

ONLYOFFICE 8.1桌面编辑器 文章目录 ONLYOFFICE 8.1桌面编辑器一、ONLYOFFICE的简介二、ONLYOFFICE 8.1新功能和改进2.1 轻松编辑器 PDF 文件2.2 用幻灯片版式快速修改幻灯片2.3 无缝切换文档编辑、审阅和查看模式2.4 改进从右至左语言的支持 & 新的本地化选项2.5 隐藏“连…

【AI大模型】GPTS 与 Assistants API

前言 2023 年 11 月 6 日&#xff0c;OpenAI DevDay 发表了一系列新能力&#xff0c;其中包括&#xff1a;GPT Store 和 Assistants API。 GPTs 和 Assistants API 本质是降低开发门槛 可操控性和易用性之间的权衡与折中&#xff1a; 更多技术路线选择&#xff1a;原生 API、…

洗地机选购指南,什么品牌最值得购买?2024四大口碑品牌推荐

随着炎炎夏日的到来&#xff0c;家里的地板清洁会成为人们“沉重”的负担&#xff0c;而拥有一台能够高效又轻松完成地板深度清洁的洗地机是一件非常幸福的事儿。但是&#xff0c;面对市场上琳琅满目的洗地机品牌和型号&#xff0c;如何找到一款综合性能都不错的洗地机成为了许…

mac怎么压缩pdf文件,苹果电脑怎么压缩pdf文件大小

在当今数字化时代&#xff0c;PDF文件已成为广泛使用的文档格式之一。然而&#xff0c;PDF 文件可能会因其包含的图像、图形和其他元素而导致文件较大&#xff0c;这可能会影响文件的传输、存储和共享。因此&#xff0c;对 PDF 文件进行压缩以减小其文件大小是很有必要的。今天…

【pytorch04】创建Tensor

numpy中的数据创建tensor 数据已经在numpy中了&#xff0c;将numpy中的数据转到tensor中来&#xff0c;因为我们将使用tensor在GPU上进行加速运算 从NUMPY导入的FLOAT其实是DOUBLE类型 list中的数据创建tensor FloatTensor()和大写的Tensor()接收的是shape&#xff08;即数据的…

解析JavaScript中逻辑运算符和||的返回值机制

本文主要内容&#xff1a;了解逻辑运算符 &&&#xff08;逻辑与&#xff09;和 ||&#xff08;逻辑或&#xff09;的返回值。 在JavaScript中&#xff0c;逻辑运算符 &&&#xff08;逻辑与&#xff09;和 ||&#xff08;逻辑或&#xff09;的返回值可能并不总…

区块链学习03-空投篇

Hybrid 是与 以太坊 兼容的第 2 层区块链&#xff0c;集成了混合专家 (MoE) 框架&#xff0c;支持以即插即用的方式轻松创建和货币化 AI 代理。该平台旨在提高区块链应用程序中数据的完整性和可用性&#xff0c;支持跨各个行业开发和部署 AI 驱动的解决方案。 Hybrid 正在为其…

php上传zip压缩包到服务器并解压,解析压缩包内excel表格数据导入到数据库

需求: 1.需要管理后台将excel表格中的每条单词数据导入到数据库中. 2.每条单词数据对应的图片和音频文件需要上传到服务器中. 为了让客户上传数据方便,考虑了一下决定通过后台上传压缩包的方式实现 测试压缩包: 压缩包的目录结构 管理后台导入教材 public function upload…

kylin v10 离线安装chrome centos离线安装chrome linux离线安装谷歌浏览器

1. 先用自己联网的计算机&#xff0c;下载离线安装包&#xff0c;浏览器输入链接下载安装包&#xff1a; https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm 1.2. 信创环境不用执行下面&#xff0c;因为没网 1.3. 若为阿里云服务器&#xff0c;或服…

【速速收藏】适用于Linux系统的五个优秀PDF编辑器

PDF (Portable Document Format) 是便携文档格式的缩写&#xff0c;这是一种用于电子共享文档的标准格式&#xff0c;广泛应用于各种文档类型的存储和分发。然而&#xff0c;有时我们可能需要对PDF文档进行更改和编辑。本文将介绍五款在Linux平台上广受欢迎的PDF编辑器。 ​​…

七种不同类型测宽仪技术参数 看看哪种能用于您的产线?

在线测宽仪种类众多&#xff0c;原理不同&#xff0c;产品不同&#xff0c;型号不同&#xff0c;其技术参数也各不相同。不同的测量范围与测量精度&#xff0c;适用于不同规格的板材&#xff0c;看看您的板材能适用于哪种范围。 1、单测头平行光测宽仪 点光源发射的光经过发射…

期末成绩怎么快速发给家长

Hey各位老师们&#xff0c;今天来聊一个超级实用的话题&#xff1a;如何快速高效的向家长们传达学生的期末成绩。你可能会想&#xff0c;这不是很简单吗&#xff1f;直接班级群发个消息不就得了&#xff1f;但别忘了&#xff0c;保护学生隐私和自尊心也是很重要的哦&#xff01…

【方案】基于5G智慧工业园区解决方案(PPT原件)

5G智慧工业园区整体解决方案旨在通过集成5G通信技术、物联网、大数据和云计算等先进技术&#xff0c;实现园区的智能化、高效化和绿色化。 该方案首先构建高速、稳定的5G网络&#xff0c;确保园区内设备、人员与物流的实时连接和高效沟通。其次&#xff0c;通过工业物联网技术&…

RFID技术在人工晶体清洗台上的应用案例分析

RFID技术在人工晶体清洗台上的应用案例分析 应用背景 在医疗领域中人工晶体清洗台发挥着极为重要的作用&#xff0c;随着市场需求的持续增长、技术的不断创新、定制化趋势的加强以及环保要求的提高&#xff0c;人工晶体清洗台不免暴露出一下应用痛点需要解决。 痛点&#xff…

「动态规划」如何求最长摆动子序列的长度?

376. 摆动序列https://leetcode.cn/problems/wiggle-subsequence/description/ 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为摆动序列。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或者含两个不等元素的序列也…

720漫游工具又双叒叕上新了一批新功能

一、720漫游全景图片上传支持「自定义水印」 全景图片素材上传支持自定义水印设置&#xff0c;通过自定义水印&#xff0c;可以在全景图片上打上自定义的水印图片保护用户版权利益&#xff0c;同时强化自身品牌露出。具体操作如下&#xff1a; 打开「创建720漫游作品页」-选择…

MIL图像处理那些事:定义感兴趣区域ROI的两种方法(示例项目C#源码)

文章目录 效果展示第一种方法:通过鼠标框选GetROIForm构造函数如何缩放--MdispZoom的使用Ctr+滚轮缩放放大两倍:如何平移--MdispPan的使用双击返回ROI第二种方法:直接编辑ROI框显示ROI示例项目C#源码(百度网盘)本示例提供两种方法定义感兴趣区域ROI 效果展示 第一种方法:通过鼠…

从广州到上海|荣载光的智慧 与SSHT共同探索智能照明更多想象空间

随着生活水平的提高&#xff0c;大众对高品质生活的追求脚步逐步加快&#xff0c;人们对智能照明的需求日益多样化&#xff0c;不再仅仅满足于传统的照明功能&#xff0c;而是转向智能照明系统&#xff0c;提出更高的需求。 展望未来&#xff0c;中国智能照明市场预计将迎来全…

定时触发-uniapp + uniCloud 订阅消息实战教程(三)

上一节已经对云函数有了一定的了解&#xff0c;但是&#xff0c;为了发送订阅消息&#xff0c;只会云函数还是差了那么一点意思&#xff0c;所以接下来的这一节&#xff0c;将带领大家熟悉一下定时触发。 熟悉定时触发 如果云函数需要定时/定期执行&#xff0c;即定时触发&…

云计算【第一阶段(19)】磁盘管理与文件系统 LVM与磁盘配额(二)

目录 一、LVM概述 1.1、LVM机制的基本概念 ​编辑 1.2、LVM的管理命令 1.3、lvm存储 两种机制 1.4、lvm应用实例 二、磁盘配额概述 2.1、设置磁盘配额 2.2.1、实现磁盘限额的条件 2.2.2、linux磁盘限额的特点 2.2.3、磁盘配额管理 一、LVM概述 1.1、LVM机制的基本概…