【C语言】详解函数(下)(庖丁解牛版)

server/2024/11/9 17:08:44/

文章目录

  • 1. 前言
  • 2. 数组做函数形参
  • 3. 函数嵌套调用和链式访问
    • 3.1 嵌套调用
    • 3.2 链式访问

1. 前言

详解C语言函数(上)的链接:http://t.csdnimg.cn/EGsfe

经过对函数的初步了解之后,相信大家已经对C语言标准库里的函数已经有初步的认知了,并且还学会了如何自定义函数。

在之前我们学过的数据类型中,有整型、字符型、浮点型、布尔类型还有数组。这就会引发一个问题,我们说形参相当于我们给函数的一个可操作的初始变量的值,而在我们之前举的例子中,我都是用整型变量作为形参。那如果我用数组作为形参,又会是怎么样的呢?那么,在本文中就会给大家介绍,数组作为形参的效果

另外,还会讲解如果函数的函数体里面还有个函数,又会是什么情况。

那么,让我们一起扬帆起航吧!!!🚢🚢🚢

2. 数组做函数形参

在使用函数解决问题时,我们肯定会遇到一种情况:对数组里面的元素进行操作。那这就意味着,我们得把数组作为参数传递给函数,让函数来帮我们处理。那在主函数把参数传递给函数的过程中,会发生什么情况呢?这难免会引起我们对此的一泡浓厚兴趣。

我们以基本现象来逐步深入问题的本质:
假如,现在要求你写一个功能:在一个函数将整个数组的内容,全部置为-1,在写一个函数打印数组的内容。

简单思考一下,不难写出主函数里面的基本框架:

#include<stdio.h>
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,10};int sz = sizeof(arr) / sizeof(arr[0]); //计算数组元素的个数set_arr(); //作用:将数组里面的元素都置为-1。里面的参数有待填写print_arr(); //作用:打印整个数组的元素。里面的参数有待填写return 0;
}

这⾥的set_arr函数要能够对数组内容进⾏设置,就得把数组作为参数传递给函数,同时函数内部在设置数组每个元素的时候,也得遍历数组,需要知道数组的元素个数。所以我们需要给set_arr传递2个参数,⼀个是数组,另外⼀个是数组的元素个数。仔细分析print_arr也是⼀样的,只有拿到了数组和元素个数,才能遍历打印数组的每个元素。

#include<stdio.h>
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); //作用:将数组里面的元素都置为-1。print_arr(arr,sz); //作用:打印整个数组的元素。return 0;
}

数组作为参数传递给了set_arr和print_arr函数了,那么这两个函数具体如何设计呢?

在此之前,我们就要得先了解数组传参的几个重要的知识点了(敲黑板,干货来了):

  1. 函数的形式参数要和函数的实参个数匹配
  2. 函数的是参数数组,形参也可以写成数组的形式
  3. 形参如果是一维数组,数组的大小可以省略不写
  4. 形参如果是二维数组,行可以省略,但列不可以省略
  5. 数组传参时,形参是不会创建新的数组的
  6. 形参操作的数组和实参的数组是同一数组

根据上述的信息,我们可以实现这两个函数了:

void set_arr(int arr[], int sz)
{int i = 0;for(i = 0; i < sz; i++){arr[i] = -1;}
}void print_arr(int arr[], int sz)
{int i = 0;for(i = 0; i< sz; i++){printf("%d ",arr[i]);}printf("\n");
}

这样的完成了我们的要求了。相信通过上述的例子和讲解,你已经大概清楚了数组作为函数的参数时,是如何设计自定义函数的形参,以及如何在函数内操作数组的了。

关于数组作为函数参数进行传参的过程中,还有更多的细节,碍于篇幅的限制,目前只需要了解到这里就已经很不错了。后续我也会写一篇关于数组作为函数参数传参细节的文章,到时候希望大家来捧场。🥺

3. 函数嵌套调用和链式访问

有些读者可能对这个概念比较陌生,那我就先讲解一下这个概念,究竟什么时函数的嵌套调用和链式访问?

3.1 嵌套调用

嵌套调用就是函数间的相互调用。说白了,就是你中有我,我中有你。
也可以这么理解,把每个函数想象成一个个乐高零件,正是因为有这么多乐高零件的相互配合、相互成全,才成就出一个巨大且精美的乐高玩具,这也就是函数嵌套调用的精髓所在。

下面我给一道题目,我们在题目中理解概念:

题目:假如我们计算某年某月有多少天?

拿到这个题目时,我们就会想,平年和闰年在2月份有区别。每个月份的天数也有区别。
根据这个思路,我们就可以设计这两个函数:
一个是用于判断年份是否位闰年,is_leap_year()
另一个是用于说明对应月份的对应天数,get_days_of_month()

int is_leap_year(int y)
{if(((y%4==0)&&(y%100!=0))||(y%400==0))return 1;elsereturn 0;
}int get_days_of_month(int y, int m)
{int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int day = days[m];if (is_leap_year(y) && m == 2)day += 1;return day;
}int main()
{int y = 0;int m = 0;scanf("%d %d", &y, &m);int d = get_days_of_month(y, m);printf("%d\n", d);return 0;
}

分析:这⼀段代码,完成了⼀个独⽴的功能。代码中反应了不少的函数调⽤:

  • main 函数调⽤ scanfprintfget_days_of_month
  • get_days_of_month 函数调⽤ is_leap_year

未来的稍微⼤⼀些代码都是函数之间的嵌套调⽤,但是函数是不能嵌套定义的

3.2 链式访问

所谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。

这个其实也很好理解,比如:你现在接收到一个任务,你需要把一个待卡扣绳子的一端,扣在另一根绳子上。这个"卡扣"就是一个函数的返回值,"被扣的那个绳子"就是另一个函数。它们相互配合,共同完成了一个任务。

下面写一个链式访问(说不定,你在不经意间就已经用过了)的情况:

#include<stdio.h>
#include<string.h>
int main()
{printf("%d\n", strlen("I love learning C!")); //链式访问return 0;
}

下面我给大家一段有趣的代码,大家下来可以自己思考一下:

#include <stdio.h>
int main()
{printf("%d", printf("%d", printf("%d", 43)));return 0;
}

想要知道这个结果,接得先了解printf函数的返回值。这时候,你也许会惊讶,真的假的,我用了这么久的的printf函数,竟然都不知道printf函数还有返回值。

其实是有的,不信的话,可以去官网找一下这个函数的文档。为了方便研究,我就帮大家找好了。
printf函数
printf函数
看到这里,你就清楚了,printf函数返回的是被成功打印屏幕上的字符的个数。

上⾯的例⼦中,我们就第⼀个printf打印的是第⼆个printf的返回值,第⼆个printf打印的是第三个printf的返回值。

第三个printf打印43,在屏幕上打印2个字符,再返回2
第⼆个printf打印2,在屏幕上打印1个字符,再放回1
第⼀个printf打印1
所以屏幕上最终打印:4321

最后的最后,如果觉得文章写的还不错的话,请多多点赞。你们的认可是我前进和分享知识的动力之一。🙏🙏🙏


http://www.ppmy.cn/server/48028.html

相关文章

『大模型笔记』FlashAttention: 具有IO意识的快速且内存高效的精确注意力机制!

Flash Attention的工作,即快速且内存高效的具有IO感知的精确注意力机制! 文章目录 一. 引言1. Flash Attention要点2. 动机:对更长的序列进行建模二. FlashAttention: 具有IO意识的快速且内存高效的精确注意力机制1. Background: Attention is the Heart of Transformers1.1…

Github 2024-06-06 Go开源项目日报 Top10

根据Github Trendings的统计,今日(2024-06-06统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目10Ollama: 本地大型语言模型设置与运行 创建周期:248 天开发语言:Go协议类型:MIT LicenseStar数量:42421 个Fork数量:2724 次关注人…

小索引大力量,记一次explain的性能优化经历

在 MySQL 的生产环境中&#xff0c;性能问题是一个常见的挑战。当数据库查询响应时间变慢&#xff0c;或者系统资源消耗异常时&#xff0c;我们需要快速定位问题并进行优化。MySQL 提供了一个强大的工具——EXPLAIN&#xff0c;它可以帮助我们分析查询语句的执行计划&#xff0…

IDEA 开发中一些好用的插件

CodeGlance&#xff1a;这是一款侧边小面板插件&#xff0c;显示代码概览&#xff0c;方便快速浏览文件结构。 Live Templates&#xff1a;用于创建预定义代码片段&#xff0c;提高输入效率&#xff0c;比如常见的方法、变量名模板。 Git Integration&#xff1a;深度集成 Gi…

LabVIEW传感器虚拟综合实验系统

LabVIEW传感器虚拟综合实验系统 开发了一个基于LabVIEW的传感器虚拟综合实验系统&#xff0c;该系统集成了NIELVIS和CSY系列传感器实验平台&#xff0c;通过图形化编程语言进行数据处理和实验管理。系统允许用户进行多种传感器参数的测量和实验报告的自动生成&#xff0c;支持…

前端的三大主流框架

随着前端技术的不断演进&#xff0c;开发者们对高效、便捷且强大的框架的需求日益增加。Angular、React和Vue作为当前前端领域的三大主流框架&#xff0c;各自以其独特的优点和特性&#xff0c;满足了不同场景下的开发需求。 一、Angular Angular&#xff0c;原名AngularJS&am…

yolov8使用:数据格式转换(目标检测、图像分类)多目标跟踪

安装 yolov8地址&#xff1a;https://github.com/ultralytics/ultralytics git clone https://github.com/ultralytics/ultralytics.git安装环境&#xff1a; pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple目标检测 标注格式转换 若使用 labelimg…

Java线程池

线程池 什么是线程池 线程池就是管理一系列线程的资源池。当有任务要处理时&#xff0c;直接从线程池中获取线程来处理&#xff0c;处理完之后线程并不会立即被销毁&#xff0c;而是等待下一个任务。 为什么要用线程池 线程池提供了一种限制和管理资源的方式&#xff0c;每…