函数(2)

简介: 函数(2)

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

函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。

1.1嵌套调用

即定义一个函数的时候,里面可以调用别的函数;但是定义一个函数的时候,不能在里面定义另一个函数。(即可以嵌套调用,不能嵌套定义)

1.2 链式访问

把一个函数的返回值作为一个函数的参数

上面这个图片,两个printf都可以打印出来 3 。第二个printf就是把strlen这个函数的返回值,作为printf的第二个参数。(上图中的②就是printf的第一个参数,①就是printf的第二个参数)

代码展示:

1. #include <stdio.h>
2. int main()
3. {
4.  printf("%d", printf("%d", printf("%d", 43)));
5.  return 0;
6. }

打印的结果是:4321

调用printf函数,显示的是字符的个数。

代码分析:

两次调用printf

最里面的那个printf首先在屏幕打印出来43,然后因为调用printf(调用printf函数,显示的是字符的个数),所以,变成了

printf("%d", printf("%d", 2),然后,再在屏幕上显示2,调用printf函数(调用printf函数,显示的是字符的个数),所以变成了printf("%d", 1),再在屏幕上显示1,所以最后的结果显示的是4321.

二 函数的声明和定义

2.1 函数的声明

(1)告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。

(2)函数声明一般出现在函数使用之前。要满足,先声明后使用。

(3)函数的声明一般要放在头文件里。

2.2 函数的定义

函数的定义是指函数的具体实现,交代函数功能的实现。

定义函数放在前面 代码展示:

1. 
2. #include <stdio.h>
3. int Add(int a, int b)
4. {
5.  int c = 0;
6.  c = a + b;
7.  return c;
8. }
9. int main()
10. {
11.   int a = 20;
12.   int b = 30;
13.   int ret = Add(a, b);
14.   printf("%d ", ret);
15.   return 0;
16. }

定义函数放在后面 代码展示:

1. #include <stdio.h>
2. int Add(int a, int b);//函数的声明
3. int main()
4. {
5.  int a = 20;
6.  int b = 30;
7.  int ret = Add(a, b);
8.  printf("%d ", ret);
9.  return 0;
10. }
11. 
12. int Add(int a, int b)
13. {
14.   int c = 0;
15.   c = a + b;
16.   return c;
17. }

定义的函数如果放在前面,就不需要声明,如果放在后面,就需要提前声明,否则就会报错。

一般都是采用分文件的方法书写。函数声明放在头文件1.h里,定义的函数,自己一个文件2.c,在别的文件里使用时需要 #include "头文件1".

函数递归(这个非常重要)

3.1 什么是递归?

程序调用自身的编程技巧成为递归。(函数自己调用自己就是递归)

递归作为一种算法在程序设计语言中广泛使用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略,只需少量的程序就可描述出解决过程所需要的多次重复计算,大大的减少了程序的代码量。

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

3.2 递归的两个条件

(1)存在限制条件,当满足这个限制条件的时候,递归便不再继续。

(2)每次递归调用之后越来越接近这个限制条件。

3.2.1 练习1

接受一个整形值(无符号),按照顺序打印它的每一位。

例如:输入1234,输出1 2 3 4

代码展示:

1. #include <stdio.h>
2. void print(unsigned int n)
3. {
4.  if (n > 9)
5.  {
6.    print(n / 10);
7.  }
8.  printf("%d ", n % 10);
9. }
10. int main()
11. {
12.   unsigned int num = 0;
13.   scanf("%d", &num);
14.   print(num);
15.   return 0;
16. }

知识点:

unsigned int   输出的时候用%u

3.2.2 练习2

编写函数不允许创建临时变量,求字符串的长度。

代码1展示:(这个代码不符合题意,因为含有临时变量count)

1. #include <stdio.h>
2. int my_strlen(char* s)
3. {
4.  int count = 0;
5.  while (*s != '\0')
6.  {
7.    count++;
8.    s++;
9.  }
10.   return count;
11. }
12. int main()
13. {
14.   char arr[] = "abc";
15.   int len = my_strlen(arr);
16.   printf("%d", len);
17.   return 0;
18. }

知识点:

如果是int类型,s+1,跳过4个字节。double也是+1,跳过8个字节。

代码2展示:

1. #include <stdio.h>
2. int my_strlen(char* s)
3. {
4.  if (*s == '\0')
5.    return 0;
6.  else
7.    return 1 + my_strlen(s + 1);
8. }
9. int main()
10. {
11.   char arr[] = "abc";
12.   int len = my_strlen(arr);
13.   printf("%d", len);
14.   return 0;
15. }

3.3 递归与迭代

迭代就是不断的重复,就是不是递归的方法。

3.3.1 练习3

求n的阶乘 (不考虑溢出)

代码展示:

循环的方法 代码展示:

1. #include <stdio.h>
2. int main()
3. {
4.  int i = 0;
5.  int n = 0;
6.  scanf("%d", &n);
7.  int ret = 1;
8.  for (i = 1; i <= n; i++)
9.  {
10.     ret = ret * i;
11.   }
12.   printf("%d", ret);
13.   return 0;
14. }

递归的方法 代码展示:

1. #include <stdio.h>
2. int fac(int n)
3. {
4.  if (n <= 1)
5.    return 1;
6.  else
7.    return n * fac(n - 1);
8. }
9. int main()
10. {
11.   int n = 0;
12.   scanf("%d", &n);
13.   int ret = fac(n);
14.   printf("%d", ret);
15.   return 0;
16. }

4!= 4 *3!     3! = 3*2!

3.3.2 练习4

求第n个斐波那契数列 (不考虑溢出)

代码1展示:(递归的方法)

1. #include <stdio.h>
2. int fib(int n)
3. {
4.  if (n <= 2)
5.    return 1;
6.  else
7.    return fib(n - 1) + fib(n - 2);
8. }
9. int main()
10. {
11.   int n = 0;
12.   scanf("%d", &n);
13.   int ret = fib(n);
14.   printf("%d", ret);
15.   return 0;
16. }

这种方法,如果求第50个斐波那契数,需要花费大量的时间 说明用递归的方法不是简单的方法

在调用函数的时候,如果参数过大,那就会报错:stack overflow (栈溢出)这样的信息。

系统分配给程序的栈空间是有限的,当时出现了死循环,或者(死递归),这样可能导致一直开辟栈空间,最终导致栈空间耗尽的现象,这样的情况我们称之为栈溢出。

代码2展示:(用循环的方法)

1. #include <stdio.h>
2. int fib(int n)
3. {
4.  int a = 1;
5.  int b = 1;
6.  int c = 0;
7.  while (n > 2)
8.  {
9.    c = a + b;
10.     a = b;
11.     b = c;
12.     n--;
13.   }
14.   return c;
15. }
16. int main()
17. {
18.   int n = 0;
19.   scanf("%d", &n);
20.   int ret = fib(n);
21.   prntf("%d", ret);
22.   return 0;
23. }

许多问题是可以用递归的形式解释的,但只是因为它比非递归的形式更为清晰,但是这些问题的迭代实现往往比递归效率更高,虽然代码的可读性稍微差些。

当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可弥补它所带来的运行时开销。

函数就到此结束了,希望友友们可以提出宝贵的的意见。

相关文章
|
8天前
|
程序员 C语言
函数(1)
函数(1)
14 0
|
1月前
|
Java 测试技术 Python
为什么要用函数
在编程中,函数是一种重要的抽象工具,它使我们能够组织和复用代码,提高代码的可读性、可维护性和效率。函数允许我们将一段代码块封装起来,给它一个名字,并通过参数和返回值来与外部世界交互。下面,我们将深入探讨为什么要使用函数,并附上相应的代码示例。
25 1
|
1月前
|
存储 编译器 Serverless
C++系列十:函数
C++系列十:函数
|
1月前
|
数据库
什么是纯函数
纯函数是指在相同的输入下,总是返回相同的输出,且没有副作用的函数。具体来说,纯函数不会改变任何传入的参数,也不会在函数外部改变全局变量、文件系统、数据库等状态,它只是接收输入并返回输出,不会产生任何可观察的副作用。
24 0
|
1月前
|
前端开发 JavaScript
Less的函数的介绍
Less的函数的介绍
32 0
|
6月前
|
人工智能
函数练习
用菜单的形式分别选择百钱买百鸡,九九表,水仙花数。
32 0
|
11月前
|
程序员 C语言 C++
函函函函函函函函函函函数——one
函函函函函函函函函函函数——one
64 0
|
算法 编译器
函数(二)
函数(二)
64 0
函数(二)
|
SQL 分布式计算 关系型数据库
not_in函数致错
Not in 函数-致错 我们开发当中有些业务逻辑会用到not in()这个函数, 岗位角度:不管是后端开发还是大数据开发还是数据分析师… 技术角度:不管是Mysql、Hive、Maxcompute…
128 0
|
存储 数据采集 索引
再遇函数
简介:学习python的学习笔记 3,在B站《求知学堂》学习。
再遇函数