大家好,欢迎来到IT知识分享网。
一、什么是函数?
注意:关于函数之间的关系
① main()函数是主函数,也是一个函数,但无论是什么函数,函数与函数之间都是并列关系,它们之间可以相互调用,但关系仍然是并列的,(函数2对函数1说:我可以去帮你,但你不能妄想拥有我!)
② 此图中,函数1,2,3之间都是并列的关系,函数2,3是前来帮助函数1(main函数)的,而不是函数1拥有函数2,3。
同理,如果函数2中也有地方需要用到计算差的功能,它也可以找函数3帮忙(调用)。
二、函数基本形式
函数基本内容有:返回值类型,函数名称,形参,返回值。
- 函数名称: 一个函数必须要有名字,不然很多函数无法辨别,而且想要调用这个函数总得需要一个名字。(就像人得有名字一样,不然人与人直接怎么相互称呼,相互辨别啊!)
- 形式参数(形参): 传入这个函数的数据。比如,一个计算两个数字和的函数,我想要通过这个函数计算和,就要知道到底要计算谁和谁的和,那就需要你给我两个数,然后我通过这个函数来给你计算,所以,算
7和5的和,那我要把7,5这两个数据传给计算和的这个函数,形参就是起传递数据的作用的。 - 返回值: 通过函数运算后,想要传回的数据。比如,上个例子,我将
7,5传给计算和的函数后,在该函数中经过运算,得到了一个结果——它们的和12,现在需要将这个和返回给之前调用该函数的地方,那就需要一个返回值了,我们正是要返回和12。 - 返回值类型: 就是返回值的类型,根据返回值来确定。比如,上个例子,我们返回
12,就是一个int类型的数据,所以我们这个函数的类型(同时也是返回值类型)也就是int型的了。
三、C语言中函数的分类
- 库函数:
别人写的,可以直接用。 - 自定义函数:
自己写的,根据自己的需要自定义写函数。
1.库函数
C语言中把常用的功能进行了封装,封装成一个个的函数,提供给大家使用。
库函数的规定和实现
C语言并不直接实现库函数,而是提供C语言标准和库函数的约定,由编译器具体实现各种库函数。
C语言规定了一个函数的功能,函数名称,形式参数,返回值类型。
(相当于,用户想要一辆车,C语言提供车的标准:车长,车宽,车的颜色…但并不具体造这辆车,让谁造呢?让编译器来具体造出实体车给用户)
注意: 在不同编译器中,使用一个相同的函数,功能可能一样,但内部功能实现的逻辑可能不同。
库函数的使用
1. 使用必须加头文件 :
因为库函数不是我们自己写的,比如:使用printf()函数,需要加上 #include<stdio.h>
int main() {
//使用printf()的库函数 printf("hehe!\n"); return 0; }
常用库函数分类
IO函数,字符串操作函数,字符操作函数,内存操作函数,时间/日期函数,数学函数,其他库函数
2.自定义函数
与库函数的区别就是,函数的名称,形参,返回值类型都可以自己定义。(自己的函数,想叫什么名字叫什么名字,想设置几个参数就设置几个参数)
自定义函数分类
- 值传递: 传递给函数数据,不改变实参
- 址传递: 传递给函数地址,可以改变实参
值传递
下面看一段代码,理解一下:
#include<stdio.h> int mul(int num1, int num2) {
int m = num1 * num2; return m; } int main() {
int a = 3; int b = 6; int c = mul(a, b); printf("%d\n",c); }
址传递
下面看一段代码,理解一下:
#include<stdio.h> void swap(int* p1, int* p2) {
int temp; temp = *p1; *p1 = *p2; *p2 = temp; } int main() {
int c = 200; int d = 100; swap(&c, &d); printf("c = %d,d = %d\n", c, d); return 0; }
定义函数时应该值传递还是址传递
看是否需要改变实参的值,需要改动就定义址传递函数,不需要就定义值传递函数。
3.实参和形参
形参的创建和销毁
- 形式参数只有在调用函数时,才分配空间(栈区),而不调用函数时,只是形式上存在,并没有实例化。
- 在函数调用结束后,形参立即销毁。
- 形参存储在内存中的栈区。
实参
四、函数的调用
上述过程中,其实已经包括了函数的调用。
传值调用
传址调用
五、函数的嵌套
1.函数定义和函数调用区分
函数定义:创建某个函数。(盖房子)
函数调用:使用某个函数。(住进房子里)
2.嵌套调用和嵌套定义
函数嵌套定义
函数嵌套定义:在一个函数中定义一个函数。
该代码是在 main() 函数中,定义了一个名为 hell() 的函数。可以看出来 hell() 和 main() 两个函数是包含关系,这是不允许的。
函数嵌套调用
函数嵌套调用:在一个函数中使用一个函数。
该代码是在 main() 函数中,调用了一个名为 hell() 的函数。可以看出来 hell() 和 main() 两个函数是并列关系,这是可以的。
六、链式访问
函数链式访问:一个函数的返回值作为另一个函数的参数。
示例:
printf() 函数的返回值是打印数字和字符的个数。
解释:
示例延展:
在每个 printf() 函数中的 %d 后了一个空格,空格也是一个字符。
解释:
七、函数声明
1.什么时候进行函数声明
2.函数声明的格式
形参部分可以直接写类型,不用标明类型名称。如,int sum( int ,int );
示例:
3.函数声明和函数定义的区别
声明就是告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
4.函数声明一般放在头文件中
一般将函数声明放到头文件中,将函数定义放到源文件中,在函数调用的文件中包含头文件,就可以用了。
八、函数递归
程序调用自身的编程技巧称为递归( recursion),它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
示例:
示例1:
main() 函数中调用 main() 函数
结果:
无限打印 hehe!,最后死递归了,会栈溢出。
每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
示例2:
接受一个整型值(无符号),按照顺序打印它的每一位,(输入:1234,输出:1 2 3 4)
方法1:
利用数组,将该数字的每一位得到,放到一个数组中,然后打印数组。
#include<stdio.h> int main() {
int a = 0; int i = 0; int arr[10]; scanf_s("%d", &a); while (a ) {
arr[i] = a % 10; i++; a /= 10; } for (i = i - 1; i >= 0; i--) {
printf("%d ", arr[i]); } return 0; }
结果:
方法2:
利用递归函数,定义一个函数,print(unsigned int x)会打印出无符号整形 x 的每一位。
假设要打印数字 3426 的每一位,就是打印 342 的每一位再打印一个 6;同理,打印 342,就是打印 34,再打印一个 2 就可以了。
#include<stdio.h> void print(unsigned int a) {
if (a / 10 == 0) printf("%d ", a); else {
print(a / 10); printf("%d ", a % 10); } } int main() {
unsigned int a = 0; scanf_s("%d", &a); print(a); return 0; }
结果:
示例3:
求第 n 个斐波那契阿数是多少。
方法1:
用递归的方法,第 n 个斐波那契数是第 n-1 和第 n-2 的和,那求第 n 个斐波那契数,就要先求第 n-1 和 第 n-2 个。
#include<stdio.h> int feibo(int n) {
if (n == 1 || n == 2) return 1; else {
return feibo(n - 1) + feibo(n - 2); } } int main() {
int n = 0; printf("请输入 n 的值:"); scanf_s("%d", &n); printf("第%d个斐波那契数是:%d\n", n, feibo(n)); return 0; }
结果:
但是,当 n 的数值过大时,如 n = 40,程序运行速度会稍慢。
最终,也会有结果,只是速度稍慢而已,n 的值越大,就会越慢。
原因是,在计算第 n 个斐波那契数的时候,会有大量的重复计算,这些重复的计算导致运算速度较慢。
方法2:
利用循环的方式得到第 n 个斐波那契数。
#include<stdio.h> int main() {
int n = 0; int x = 0; printf("请输入 n 的值:"); scanf_s("%d", &n); if (n == 1 || n == 2) x = 1; else {
int x1 = 1; int x2 = 1; for (int i = 3; i <= n; i++) {
x = x1 + x2; x1 = x2; x2 = x; } } printf("第%d个斐波那契数是:%d\n", n, x); return 0; }
结果:
跟递归的方法比起来,此方法计算第40个斐波那契数计算量要少的多,所以速度要比递归的方法快。
通过上面的示例,我们可以得到下面几个结论:
1. 递归的条件
- 存在限制条件。当满足这个限制条件的时候,递归便不再继续。没有限制条件就会造成死递归。
- 每次递归调用之后都越来越接近这个限制条件。
即上面示例中的最后一层,如打印函数 print() 中,当形参是一位数时,就会直接打印,不再递归;求第 n 个斐波那契数中,当 n == 1 或 n == 2 时,会直接返回 1,而不是继续递归。
2. 递归与循环的关系
3. 迭代与循环的关系
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
循环是迭代的一种。
4. 采用迭代还是递归
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118508.html
![C语言函数详解插图1 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e1cc8ecd6ea07f576b04e3f9c48cb218.png#pic_center)
![C语言函数详解插图3 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e387c889505c1ba0098a63f074648775.png#pic_center)
![C语言函数详解插图5 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f3090e35012e9c08b5459d1f293961f8.png#pic_center)

![C语言函数详解插图9 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f3106f978a0ad71a326f20e5889e553e.png#pic_center)
![C语言函数详解插图11 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/eaff5c89aeba8ce1a40c068cc0e93c0d.png#pic_center)
![C语言函数详解插图13 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ecf2f9e79045a60c01d0f594f5fbcf9a.png#pic_center)
![C语言函数详解插图15 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f96a5b83a2afe42672f63508758b30e6.png#pic_center)
![C语言函数详解插图17 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ec048486765ca1a71b577922ddd17f07.png#pic_center)




![C语言函数详解插图27 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/2dd8604c10f26d5064abd1a786289d89.png#pic_center)
![C语言函数详解插图29 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/4c87a42c5a71510a0e3877a8c96e07cb.png#pic_center)
![C语言函数详解插图31 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/f8b117cfa5d72f7e10552847fae7bb29.png#pic_center)
![C语言函数详解插图33 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/5765c1e4b23f2d9ff6b65b6bfebe23f5.png#pic_center)
![C语言函数详解插图35 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/77965a3715b27adee07b962e01745713.png#pic_center)


![C语言函数详解插图41 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/6df6871c102672b73d13b160c87e73ac.png#pic_center)
![C语言函数详解插图43 [Alt]在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ce8207fa814fd996362f0caf3ba13be9.png#pic_center)

![C语言函数详解插图47 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/ae9e98a80e88ad7e64c0c87ef70deb08.png#pic_center)




![C语言函数详解插图57 [Alt]](https://i-blog.csdnimg.cn/blog_migrate/574aed644fa023ce8dfdd968719406ac.png#pic_center)


