【C函数】函数详解

news/2024/5/19 4:52:02/文章来源:https://blog.csdn.net/m0_70088010/article/details/128421712

函数

  • 前言
  • 一、函数是什么
  • 二、C语言中函数的分类
    • (一)库函数
      • 1.printf类
      • 2.strcpy类
      • 3.math类
      • 4.概念
      • 5.小知识
      • 6.总结
    • (二)自定义函数
      • 1.概念
      • 2.函数的组成
      • 3.例子1(求出两个数中的最大值)
      • 4.例子2(交换两个整数变量的内容)
      • 5.小知识
      • 6.总结
  • 三、函数的参数
    • (一)实际参数(实参)
    • (二)形式参数(形参)
  • 四、函数的调用
    • (一)传值调用
    • (二)传址调用
    • (三)练习
      • 1.写一个函数打印100到200之间的素数
      • 2.写一个函数输出1000年到2000年的闰年
      • 3.写一个函数,实现一个整形有序数组的二分查找
        • (1)详细解题思路:
        • (2)小知识:
        • (3)代码:
      • 4.写一个函数,每调用一次这个函数,就会将num的值增加
    • (四)函数调用实质
  • 五、函数的嵌套调用和链式访问
    • (一)嵌套调用
    • (二)链式访问
      • 1.概念
      • 2.常见例子:
  • 六、函数的声明和定义
    • (一)函数声明
      • 1.概念
      • 2.解析
    • (二)函数定义
    • (三)拓展(模块化开发)
  • 七、函数递归
    • (一)什么是递归
      • 1.概念
      • 2.简单代码
        • (1)史上最简单递归
        • (2)出现的问题
        • (3)推荐的网站
    • (二)递归的两个必要条件
      • 1.概念
      • 2.经典练习题1
        • (1)思路
        • (2)代码
        • (3)分析
      • 3.经典练习题2
        • (1)思路
        • (2)代码
        • (3)分析
    • (三)递归与迭代
      • 1.经典练习题3
        • (1)思路
        • (2)代码
        • (3)分析
      • 2.迭代概念
      • 3.经典练习题4
        • (1)思路
        • (2)代码
        • (3)分析
        • (4)问题
        • (5)迭代做法
      • 4.改进
      • 5.解决方法
      • 6.提示
    • (四)递归的经典题目
      • 1.汉诺塔问题
        • (1)题目描述和思路
        • (2)代码
      • 2.青蛙跳台阶问题
        • (1)题目描述和思路
        • (2)代码
  • 总结


前言

函数相信大家并不陌生,那函数具体是什么呢?函数很常见,就是大家平时用的函数,利用几个函数的分装过后,程序就会很清晰,很简单地运行,以下,听我细细讲解一下函数吧!


一、函数是什么

维基百科中对函数是这样定义的,它是一个子程序。

在计算机科学中,子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成,它负责完成某项特定任务,而且相较于其他代码,具备独立性。
一般会有输入参数并有返回值,提供对过程的封装和对细节的隐藏,这些代码通常被称为软件库。

那我们利用 MSDN app看一看函数吧!
在这里插入图片描述


二、C语言中函数的分类

(一)库函数

1.printf类

当我们编译完程序后,我们迫不及待地想要知道结果,想把这个结果打印在屏幕上一看的时候,这个时候就非常需要一个函数将这个信息按照一定的格式打印在屏幕上,这就是printf,与之相关联的是scanf(输入)。

2.strcpy类

在编译的过程中我们会频繁地做一些字符串拷贝(strcpy),比较(strcmp)和计算长度(strlen)这类函数。关于如何简单明了的知道这类库函数的使用,我放三个博客在下面大家可以去看看。
模拟strcpy函数的使用
模拟strcmp函数的使用
模拟strlen函数的使用

3.math类

在编译的过程中,我们也会进行计算,电脑计算能力一流,原因是因为它运算速度快,那我们需要引进会计算的库函数来帮助我们进行计算,例如pow函数可以计算一个数的n次方。

4.概念

标准库 - 提供了C语言的库函数。
如果大家都运用这些函数,都用的是printf,strlen,pow这类函数,那是不是直接放到标准库里面,我们用的时候只需要去一调用,直接一行代码就可以使用了,是非常方便的,提高了可移植性和提高程序的效率。那假如说同样都是pow函数,中国程序员写:ncifang(),而英国程序员写:pow(),这样是不是有差异了,中国程序员看不懂英国程序员写的,英国程序员看不懂中国程序员写的,这可移植性是很差的,写的程序给别人别人看不懂那一大串是啥意思,这时候标准库的出现解决了这一问题,只需要有一样的标准即可,大家都可以调用这个函数且大家都能看懂,方便多了。

5.小知识

如何学习库函数的使用:
法一:下载MSDN软件,进行索引查询
法二:访问库函数查询网站

法三:访问库函数查询网址2(英文版)或库函数查询网址3(中文版)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.总结

1.C语言常用的库函数有:
I/O函数 – input/output 输入输出函数 例如:scanf,printf
字符串操作函数 – strlen,strcmp,strcpy
字符操作函数 – 大小写转换/字符分类
内存操作函数 – memcpy,memmoove,memset
时间/日期函数 – time
数学函数 – pow,sqrt
其他库函数
2.要借助工具学习库函数,在小知识中已经包含了。
3.英文很重要,要看得懂文献。

(二)自定义函数

1.概念

要是所有都可以使用库函数,都从一个标准库里面能够调出来,那程序员不是失业了吗?所以随之而来的是有了自定义函数,就是程序员可以自己写函数并进行调用,但是函数名需要让大家能够看懂,如果写了几千行代码的函数,其函数名叫a,好家伙,程序员得看几千行代码才能知道这个a函数是干啥的,那如果你命名很通俗易懂,那很简单,程序员拿到函数的程序,稍微一检查,直接调用,是不是很方便呢?

2.函数的组成

ps:(*)表示还有很多,是等等的意思。
在这里插入图片描述

3.例子1(求出两个数中的最大值)

代码如下:

#include<stdio.h>
//写一个函数可以找出两个整数中的最大值//定义函数
int Max(int x,int y) {if (x > y) {return x;}else {return y;}
}int main() {int a = 0;int b = 0;//输入scanf("%d %d", &a, &b);  //推演函数的使用场景//找出a和b中的最大值int max = Max(a, b); //传参//打印printf("%d\n", max);return 0;
}

以下是函数框架所代表的信息,与函数的组成相一致:
在这里插入图片描述

以下为函数调用过程图:
在这里插入图片描述

调试结果如下:
在这里插入图片描述
在这里插入图片描述

4.例子2(交换两个整数变量的内容)

这个例子不用函数编写其实很简单,但是一旦利用函数那么就要有所讲究了,不能是简单的传值的操作,而应当是传地址的操作。这一部分涉及到了函数的栈帧的创建与销毁,进入调试窗口你会发现底下两个变量的地址与进入函数的那两个变量的地址不相同,大家有兴趣可以去看一下函数栈帧与创建的博客。

函数栈帧的创建与销毁

相信大家看完那篇博客,已经对函数有了更深的理解,接下来,看一个错误示范寻找一下问题。
在这里插入图片描述
修改了x,y之后怎样,a和b的值没有进行改变,你只是交换的是形参的值,在内存中形参也是有地址存储的,它们进行改变没有影响实际参数的值,所以结果不变,可以说形参只是实参的一份临时拷贝是完全没有错误的。

那怎么做呢?那就用取地址呀,取到那个地址,使函数外部变量与函数内部变量产生联系,在同一个空间进行交换不就能做了吗?大家可能会有点疑惑,这个指针似乎不理解,其实大家只需要知道取了那个变量的地址存放到另一个变量中,在对这个变量进行修改即可,即:
在这里插入图片描述
如果大家还想提前深入了解指针,我放一篇博客供大家先去预习一下。
初阶指针

接下来我们回来,进行交换值的操作:

在这里插入图片描述
其实设计的很巧妙,是把a,b的地址找两个变量进行存放,再通过这个地址去找到a,b这两个变量,引入tmp进行交换。相当于给两个人两个门牌号,通过这个门牌号去找到房间里面的人并进行交换。

代码如下:

void Swap(int* x, int* y) {int tmp = *x;*x = *y;*y = tmp;
}int main() {int a = 0;int b = 0;//输入scanf("%d %d", &a, &b);//交换前printf("交换前:a=%d b=%d\n", a, b);//交换Swap(&a, &b);//输出printf("交换后:a=%d b=%d\n", a, b);return 0;
}

5.小知识

Q1.如何调出监视窗口?
答:先按F10,再去找如下图所示:
在这里插入图片描述

Q2.如何进入函数?
答:按F11进入函数内部。

Q3.为什么我的F10和F11按了以后锁屏幕了!?
答:因为刚开始的电脑没那么多的娱乐化按键,大多数都是进行编译用的,但电脑逐渐普及了以后,电脑生产厂商看大家都不怎么用这几个按键,那好嘛,就全部换成了调节声音,调节屏幕亮度,锁屏等此类的按键了,那怎么解决这个问题呢?其实很简单,按Fn+F10即可,因为Fn为辅助按键,一起按电脑才知道原来执行的是这个命令。

6.总结

在进行函数的使用的时候,一定要根据函数的构成每一步都不能落下,一旦落下,编译器就会报错。那当然,如果你不想传参或者不需要返回值,那很简单,写一个void哦,千万不能不写,返回类型不写的话编译器默认返回值是int类型,而参数那里什么都不写的话,编译器直接报错。
例如:在这里插入图片描述
在这里插入图片描述


三、函数的参数

(一)实际参数(实参)

真实传递给函数的参数,叫实参。
实参可以是:变量、常量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
在这里插入图片描述

(二)形式参数(形参)

形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的时候才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。

形参实例化之后其实相当于实参的一份临时拷贝。


四、函数的调用

(一)传值调用

函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参,就例如上面所讲的Max函数,是传值调用。

(二)传址调用

传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。就例如上面所讲的交换两个整数变量的内容的Swap函数一样。

(三)练习

1.写一个函数打印100到200之间的素数

//输出100到200之间的素数
#include<stdio.h>
#include<math.h>is_prime(int i) {int j = 0;for (j = 2; j < sqrt(i); j++) {if (i % j == 0) {return 0;  //不是素数}}return 1;  //是素数
}int main() {int i = 0;for (i = 100; i <= 200; i++) {//判断i是不是素数if (is_prime(i)) {printf("%d ", i);}}return 0;
}

2.写一个函数输出1000年到2000年的闰年

//写一个函数判断一年是不是闰年
// 
//1.能被4整除,并且不能被100整除为闰年
//2.能被400整除为闰年
//
int is_loop(int i) {if ((i % 400 == 0) || (i % 100 != 0) && (i % 4 == 0)) {return 1;}else {return 0;}
}int main() {int i = 0;for (i = 1000; i <= 2000; i++) {//判断i是不是闰年//是闰年返回1//不是闰年返回0if (is_loop(i)) {printf("%d ", i);}}return 0;
}

3.写一个函数,实现一个整形有序数组的二分查找

(1)详细解题思路:

在这里插入图片描述
在这里插入图片描述

(2)小知识:

sizeof是求元素的占内存空间的字节长度。
在这里插入图片描述

(3)代码:

//写一个函数,实现一个整形有序数组的二分查找#include<stdio.h>int binary_search(int arr[], int k, int sz) {int left = 0;int right = sz - 1;while (left <= right) {int mid = (left + right) / 2;if (arr[mid] < k) {left = mid + 1;}else if (arr[mid] > k) {right = mid - 1;}else {return mid;  //返回下标}}return -1; //找不到
}
int main() {int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 0;scanf("%d", &k);  //输入需要找的值int sz = sizeof(arr) / sizeof(arr[0]); //算出数组元素个数,数组总体元素的字节长度除以数组第一个元素字节的长度//找到就返回下标//找不到返回-1int pos = binary_search(arr, k, sz);if (-1 == pos) {printf("没找到\n");}else {printf("找到了,下标为:%d\n", pos);}return 0;
}

4.写一个函数,每调用一次这个函数,就会将num的值增加

//写一个函数,每调用一次这个函数,就会将num的值增加#include<stdio.h>void Add(int* p) {//*p = *p + 1;(*p)++;
}int main() {int num = 0;Add(&num);printf("%d\n", num);  //1Add(&num);printf("%d\n", num);  //2Add(&num);printf("%d\n", num);  //3return 0;
}

(四)函数调用实质

在这里插入图片描述

就好像,你在看一个电影,看到20分钟的时候,妈妈叫你去打瓶酱油,你先摁下暂停键,再去打酱油,打完酱油回来再摁开始键继续看电影,这是一个顺序的问题,在一个时间轴上,只有干完这件事,才继续去干原先是事。


五、函数的嵌套调用和链式访问

(一)嵌套调用

先举个小栗子:
在这里插入图片描述

函数之间是可以互相调用的,调用了一个函数以后,我们又需要在这个函数里再调用一个函数进行另外的计算,但是切记,函数不能嵌套定义,就是不能在函数内部再定义一个函数(在一个函数内部再写一个函数的内容),因为每个函数之间都是平等的,是平等的关系。

(二)链式访问

1.概念

定义:把一个函数的返回值作为另一个函数的参数。

举个例子:
在这里插入图片描述

2.常见例子:

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

大家可以想想这个奇怪的式子打印出来的是什么?
接下来分析一下,大家有了上面概念的基础的加持,知道打印的是另一个函数的参数,那就是printf的参数咯!那我们打开MSDN一看关于printf函数的描述和返回值。
在这里插入图片描述
发现,printf的返回值是所指向的字符数,那就好办了,先打印43,43俩字符,打印2,2一个字符,再打印1。
在这里插入图片描述
在这里插入图片描述


六、函数的声明和定义

(一)函数声明

1.概念

1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
2.函数的声明一般出现在函数的使用之前。要先声明后使用。
3.函数的声明一般要放在头文件中的。
4.声明中可以不加形参的名字,只要形参的类型即可。

2.解析

大家可能在看书或者做题的时候不像我上面写的那些函数那样,很多情况都是以下代码:

#inclue<stdio.h>//函数的声明
int Add(int x, int y);int main() {int a = 0;int b = 0;scanf("%d %d", &a, &b);int ret = Add(a, b);printf("%d\n", ret);return 0;
}int Add(int x, int y) {return x + y;
}

很简单,Add(int x, int y);这个就是函数的声明,那这个声明有什么用呢,或者怎么用呢?接下来我将细细分析!
在这里插入图片描述

(二)函数定义

函数的定义是指函数的具体实现,交代函数的功能实现,而函数定义也是一种特殊的声明。

//函数的定义
int Add(int x, int y) {return x + y;
}int main() {int a = 0;int b = 0;scanf("%d %d", &a, &b);int ret = Add(a, b);printf("%d\n", ret);return 0;
}

(三)拓展(模块化开发)

函数的声明和定义在很多地方不像上面所述的那么简单,而在工程当中是需要创建头文件和其他工程的,如下图所示:

创建三个文件,一个头文件,两个工程文件,即两个模块(add.c+add.h和test.c):
在这里插入图片描述

函数的主要部分放到test.c中:
在这里插入图片描述

函数的定义放到add.c中:
在这里插入图片描述

函数的声明放到头文件add.h中:
在这里插入图片描述

模块化开发的优势:
在这里插入图片描述
在这里插入图片描述

大家如果对这个模块化开发很感兴趣的话,可以看一下我写的三子棋和扫雷游戏的博客:
三子棋
扫雷


七、函数递归

(一)什么是递归

1.概念

程序调用自身的编程技巧称为递归。

递归作为一种算法在程序设计语言中广泛应用,一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。

特点:它通常是把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。

只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

递归的主要思考方式在于:把大事化小。

2.简单代码

(1)史上最简单递归

在这里插入图片描述

(2)出现的问题

在这里插入图片描述

(3)推荐的网站

stackoverflow.com
《程序员问答社区》(国外)
在这里插入图片描述
segment.com
《思否》(国内)
在这里插入图片描述

(二)递归的两个必要条件

1.概念

1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2.每次递归调用之后越来越接近这个限制条件。

2.经典练习题1

接受一个整型值(无符号),按照顺序打印它的每一位。
例如:输入1234 输出1 2 3 4

(1)思路

在这里插入图片描述

(2)代码

#incldue<stdio.h>
void Print(unsigned int num) {if (num > 9) {Print(num / 10);}printf("%d ", num % 10);
}int main() {unsigned int num = 0;scanf("%u", &num);//写一个函数打印num的每一位Print(num);return 0;
}

(3)分析

在这里插入图片描述

3.经典练习题2

模拟strlen函数,求字符串长度。
给大家分享一篇博客,是关于详解strlen函数的博客!
模拟strlen函数

(1)思路

不创建临时变量,只要第一个字符不是‘\0’,则拿出第一个字符,并求其他字符,递归下去:
arr+1表示指针指向往后移一位,*arr表示访问指向的这块空间。
在这里插入图片描述

在这里插入图片描述

(2)代码

#include<stdio.h>
int my_strlen(char* arr) {if (*arr != '\0') {return 1 + my_strlen(arr + 1);  //指针指向往后移一位}else{return 0;}}int main() {char arr[] = "bit";//{b i t \0}int len = my_strlen(arr);printf("%d\n", len);return 0;
}

(3)分析

在这里插入图片描述

(三)递归与迭代

1.经典练习题3

求n的阶乘

(1)思路

n!可以转化为n*(n-1)!来进行计算。
在这里插入图片描述

(2)代码

//写一个函数求n的阶乘#include<stdio.h>int Fac(int n) {if (n <= 1) {return 1;}else {return n * Fac(n - 1);}
}int main() {int n = 0;scanf("%d", &n);int ret = Fac(n);printf("%d\n", ret);return 0;
}

(3)分析

在这里插入图片描述
大家可能有疑问了,这个n为什么调用完变了,返回的时候那个n还是原先那个值,不是应该改变的吗?这其实涉及到了一个比较难的知识,是函数栈帧的创建与销毁,大家可以先去看看我写的关于函数栈帧创建与销毁的博客:
函数栈帧的创建与销毁

以下是简单介绍,大家看完介绍可以去看看函数栈帧的创建与销毁的那篇博客。
在这里插入图片描述
在这里插入图片描述

2.迭代概念

如果产生很大的数字,超过42亿的数了,用递归程序就容易崩掉,这是由于出现栈溢出的问题,所以就出现了迭代的思想,而迭代是什么,迭代其实就是循环,栈溢出的现象就会迎刃而解。

3.经典练习题4

求第n个斐波那契数(兔子繁殖问题)(不考虑栈溢出问题)

(1)思路

在这里插入图片描述

(2)代码

//求第n个斐波那契数(兔子繁殖问题)
//前两个数相加等于第三个数#include<stdio.h>int Fib(int n) {if (n <= 2) {return 1;}else {return Fib(n - 1) + Fib(n - 2);}
}int main() {int n = 0;scanf("%d", &n);//写一个函数求第n个斐波那契数int ret = Fib(n);printf("%d\n", ret);return 0;
}

(3)分析

在这里插入图片描述

(4)问题

递归解法太低效了,算n=50,需要好久。
我们可以看一下n=40时第三个斐波那契数需要被计算多少次:
在这里插入图片描述

(5)迭代做法

计算效率过于低,但是可以写成循环的方式,也就是迭代,速度非常快。
如下:前两个值相加赋给第三个值,然后第二个值赋给第一个值,第三个值赋给第二个值,一直加到相应的n的值。
在这里插入图片描述

#include<stdio.h>int Fib(int n) {int a = 1;int b = 1;int c = 1;while (n > 2) {c = a + b;a = b;b = c;n--;  //次数逐渐减一}return c;
}int main() {int n = 0;scanf("%d", &n);//写一个函数求第n个斐波那契数int ret = Fib(n);printf("%d\n", ret);return 0;
}

4.改进

1.在调试factorial 函数的时候,如果你的参数比较大,那就会报错:stackoverflow(栈溢出)这样的信息。
2.系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出。

5.解决方法

1.将递归改写成非递归。
2.使用static对象替代nonstatic局部对象。在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放 nonstatic 对象的开销,而且 static 对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。

6.提示

1.许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2.但是这些问题的选代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3.当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。
4.递归可以转化为迭代(循环)(非递归),这是递归与非递归之间的转换。

(四)递归的经典题目

1.汉诺塔问题

(1)题目描述和思路

在这里插入图片描述

描述:一次移动一个方块,将A柱子上面的方块全部移动到C柱子上,前提是大的方块不能压在小的方块下面。
思路:三个方块:1->C,2->B,1->B,3->C,1->A,2->C,1->C。

四个盘子就是三个盘子的递归加一个盘子,依次类推。

(2)代码

#include<stdio.h>void move(char A, char C, int n)
{printf("把第%d个方块从%c--->%c\n", n, A, C);
}void HanoiTower(char A, char B, char C, int n)
{if (1 == n){move(A, C, n);}else{//把n-1个方块从A柱借助于C柱移动到B柱上HanoiTower(A, C, B, n - 1);//把A柱子上最后一个方块移动到C柱上move(A, C, n);//把n-1个方块从B柱借助于A柱移动到C柱上HanoiTower(B, A, C, n - 1);}
}int main()
{int n = 0;printf("输入A柱子上的方块个数>\n");scanf("%d", &n);//将n个方块从A柱借助于B柱移动到C柱上HanoiTower('A', 'B', 'C', n);return 0;
}

具体我会出一篇博客细细讲解一下汉诺塔问题。

2.青蛙跳台阶问题

(1)题目描述和思路

描述:有n个台阶,青蛙一次可选择跳1个台阶或者2个台阶,那总共有多少种跳法?
思路:在这里插入图片描述
其实就是一个斐波那契数列。

(2)代码

代码如下:

#include<stdio.h>
int Add(int n) {int a = 1;int b = 2;int c = 0;while (n > 2) {c = a + b;a = b;b = c;n--;}return c;if (n <= 2) {return n;}
}int main() {int n = 0;//输入总共有多少台阶printf("请输入总共有多少个台阶>");scanf("%d", &n);//调用一个函数青蛙跳台阶次数int ret = Add(n);//打印总共跳了多少次printf("青蛙总共跳了多少次:%d\n", ret);;return 0;
}
int Add(int n) {if (1 == n) {return 1;}else if (2 == n) {return 2;}else {return Add(n - 1) + Add(n - 2);}
}int main() {int n = 0;//输入总共有多少台阶printf("请输入总共有多少个台阶>");scanf("%d", &n);//调用一个函数青蛙跳台阶次数int ret = Add(n);//打印总共跳了多少次printf("青蛙总共跳了多少次:%d\n", ret);;return 0;
}

具体关于汉诺塔问题和青蛙跳台阶问题我会再出一篇博客细细讲解。


总结

如果说指针是C语言的灵魂,那么函数就是C语言的根本,函数在C语言当中是很重要的,我们重点分析了递归,递归难度很大,要慢慢理解。这一单元,我们详细了解了函数就是在栈区开辟一块属于自己的空间并进行运算,大家最需要了解到的是函数栈帧的创建与销毁,还有就是需要看一部分指针的内容,可以不用看的很熟练,后续的指针单元讲解大家会很轻松的掌握指针的。


客官,码字不易,来个三连支持一下吧!!!

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

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

相关文章

三、SpringBoot启动流程及自动化配置

一、Springboot启动流程 图一:Springboot项目的启动流程 首先,针对上图中自己不太明确的两个知识点,这里做如下总结: 1.Banner:参考这篇文章:SpringBoot之Banner介绍 - MarkLogZhu - 博客园 (cnblogs.com) ; 2.钩子方…

HRTransNet阅读理解

E. Dual-direction short connection fusion module HRFormer applies transformer blocks to enlarge receptive field of fused feature Frs, and uses exchange units to absorb the merits of multi-scales features. The process is described as: HRFormer使用TRM块来扩…

程序员过圣诞 | 用HTML写出绽放的烟花

文章目录一、前言二、创意名三、效果展示四、烟花代码五、总结一、前言 2022年圣诞节到来啦&#xff0c;圣诞节是基督教纪念耶稣诞生的重要节日。亦称耶稣圣诞节、主降生节&#xff0c;天主教亦称耶稣圣诞瞻礼。耶稣诞生的日期&#xff0c;《圣经》并无记载。公元336年罗马教会…

平衡二叉树的一系列操作:删除、插入(在二叉排序树中插入新结点后,如何保持平衡)、调整平衡等等等

平衡二叉树的插入&#xff08;在二叉排序树中插入新结点后&#xff0c;如何保持平衡&#xff09;1.平衡二叉树的定义2.平衡二叉树的插入&#xff08;调整最小不平衡子树A&#xff09;2.1LL&#xff08;在A的左孩子的左子树中插入导致不平衡&#xff09;2.2RR&#xff08;在A的右…

qt嵌入并运行外部exe

由于项目需要&#xff0c;要实现将一个外部exe运行在qt的窗口中。下面记录一下过程&#xff1a; 首先就是在qt中创建一个新项目 由于我这里没有用到画布&#xff0c;所以没有勾选Generate form 然后就会自动生成一个可运行的代码 然后将我下边的代码替换粘贴进去 #includ…

cubeIDE开发, UART的CubeMX及HAL库实现原理及底层分析

一、UART通信协议 UART通用异步收发器(Universal Asynchronous Receiver and Transmitter)是STM32 上常用的串行通信外设&#xff0c;可以灵活地与外部设备进行全双工数据交换&#xff0c;需要注意区别&#xff1a; 【1】USART-通用同步异步收发器(Universal Synchronous Async…

stm32f407VET6 系统学习 day04 DHT11 温湿度传感器

1.温湿度的一次完整的数据包括&#xff1a; 一次完整的数据传输为40bit,高位先出。 数据格式: 8bit湿度整数数据 8bit湿度小数数据 8bi温度整数数据 8bit温度小数数据 8bit校验&#xff08;校验和的值是前四个字节数据的和) 用户MCU发送一次开始信号后,DHT11从低功耗模式转…

UDP协议在Windows上使用示例

UDP(User Datagram Protocol&#xff0c;用户数据报协议)是无连接的&#xff0c;因此在两个进程通信前没有握手过程。UDP协议提供一种不可靠数据传送服务&#xff0c;也就是说&#xff0c;当进程将一个报文发送进UDP套接字时&#xff0c;UDP协议并不保证该报文将到达接收进程。…

为什么要使用 Compose 来开发 Android ?

1. Compose诞生背景 近年来&#xff0c;以React为代表的声明式UI开发思想席卷了整个前端开发领域。客户端与前端在产品形态上非常相似&#xff0c;也希望借鉴这种全新的开发思想来提升客户端UI的开发效率和体验。在这个大背景下&#xff0c;Android与iOS平台相继发布了自己的声…

node.js+uni计算机毕设项目互联网教育系统小程序(程序+小程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等…

Attetion is all you need论文阅读笔记

Attetion is all you need 参考&#xff1a;沐神&#xff08; 沐神_论文精讲_Attention is all you need&#xff09; 1、Abstract 主流的序列转录模型&#xff08;给一个序列生成另一个序列&#xff0c;比如机器翻译&#xff0c;给一句英文&#xff0c;生成一句中文&#x…

Biotin-PEG-MAL,Maleimide-PEG-Biotin,生物素聚乙二醇马来酰亚胺

英文名称&#xff1a;Biotin-PEG-MAL&#xff0c;Maleimide-PEG-Biotin 中文名称&#xff1a;生物素聚乙二醇马来酰亚胺 Biotin-PEG-Mal&#xff0c;聚乙二醇化生物素对亲和素或链霉亲和素有很高的亲和力。生物素/亲和素体系在生物分子检测和分离中有着广泛的应用。马来酰亚胺…

【状态估计】电力系统状态估计中的异常检测与分类(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

LeetCode 1739. 放置盒子:数学 思维

【LetMeFly】1739.放置盒子 力扣题目链接&#xff1a;https://leetcode.cn/problems/building-boxes/ 有一个立方体房间&#xff0c;其长度、宽度和高度都等于 n 个单位。请你在房间里放置 n 个盒子&#xff0c;每个盒子都是一个单位边长的立方体。放置规则如下&#xff1a; …

408 考研《操作系统》第三章第二节:基本分页存储管理、两级页表、基本分段存储管理方式、段页式管理方式

文章目录教程1. 基本分页存储管理的基本概念1.1 连续分配方式的缺点1.2 把“固定分区分配”改造为“非连续分配版本”1.3 什么是分页存储1.4 如何实现地址的转换&#xff1f;1.5 逻辑地址结构1.6 重要的数据结构——页表1.7 知识回顾与重要考点2. 基本地址变换机构2.1 例题2.2 …

单链表的头插法与尾插法

一、基本概念 二、头叉法 该方法从一个空链表开始&#xff0c;生成新结点&#xff0c;并将读取到的数据存放到新结点的数据域中&#xff0c;然后将新结点插入到当前链表的表头。采用头插法创建单链表时&#xff0c;读入数据的顺序与生成单链表的元素顺序是相反的。 LinkList L…

JavaScript操作BOM对象

BOM&#xff1a;浏览器对象模型 window代表浏览器窗口 >window.alert(1) undefined >window.innerHeight //浏览器内部高度 242 >window.innerWidth 1229 >window.outerHeight //浏览器外部高度 824 >window.outerWidth 1536 Navigator&#xff0c;封装了浏…

Kafka消息写入流程

Kafka消息写入流程 0,写入消息简要流程图 1,从示例开始 在Kafka中,Producer实例是线程安全的,通常一个Producer的进程只需要生成一个Producer实例. 这样比一个进程中生成多个Producer实例的效率反而会更高. 在Producer的配置中,可以配置Producer的每个batch的内存缓冲区的大小…

DAY5 Recommended system cold startup problem

推荐系统的冷启动问题 推荐系统冷启动概念 ⽤户冷启动&#xff1a;如何为新⽤户做个性化推荐物品冷启动&#xff1a;如何将新物品推荐给⽤户&#xff08;协同过滤&#xff09;系统冷启动&#xff1a;⽤户冷启动物品冷启动本质是推荐系统依赖历史数据&#xff0c;没有历史数据⽆…

【工作流Activiti7】6、Activiti 7 源码学习

1. 启动分析 源码版本是 7.1.0.M6 首先从 ProcessEngineAutoConfiguration 开始 ProcessEngineAutoConfiguration 是activiti-spring-boot-starter 7.1.0.M6自动配置的入口类&#xff0c;在这里主要看 SpringProcessEngineConfiguration 主要是配置了自动部署 最最最重要的…