函数(二)

接函数(一),伙伴们大家好,欢迎大家继续C语言的学习,今天我们来讲解函数(二)的内容。本次内容包括:函数的嵌套调用和链式访问、函数的声明和定义、函数递归。

我们来进入正式内容:

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

5.1嵌套调用

函数的嵌套,函数是可以相互调用的,也就是说一个函数可以调用另一个函数。主函数可以调用任意的函数,但是其他函数是不能调用主函数。另外,函数是可以嵌套调用,而不能嵌套定义。比如下面的代码:

函数的嵌套调用,在以后的文章中会经常用到,这里我们可以先熟悉一下,慢慢的就会熟悉函数的嵌套调用,嵌套调用就是,一个函数已经实现了一个功能,而另一个函数需要这个功能,那么我们就可以调用这个函数。如下代码:

5.2函数的链式访问

函数的链式访问就是把一个函数的返回值作为另一个函数的参数。

比如下面的代码:

这就是函数的链式访问!

六、函数的声明和定义

6.1函数声明:

函数的声明就是在告诉编译器有一个函数叫什么,返回类型是什么,参数链表是什么。但是这个函数还是不存在的,也就是说还没有定义。

函数在使用时,可以放在main函数的前面或者后面,但是当放在main函数后面时需要进行函数的声明,告诉编译器有这样一个函数。让它做好准备去调用这个函数。这就是先声明后调用,放在前面时就不需要了,因为编译器是按顺序进行编译代码的。

比如以下代码:

值得注意的是,我们在编写一个很大的项目时,会有很多人协同编写这个项目,那么我们如何才能简单又快速的把每个人的代码整合到一起呢,我们可以让程序员建立专属于自己的头文件和源文件,然后头文件里面写上函数的声明,那么我们就可以在主函数所在的源文件下包含此头文件,就可以把代码整合到一起。就不用再复制粘贴了。另外,我们可以把源文件生成一个静态库,来进行代码的保密。要使用该库时,就可以把该库和它的头文件放在项目目录下,项目源文件包含此头文件,那么我们就可以使用该库里的代码了。由于生成库时,里面存储的时机器语言,在文件里表现的是一堆乱码,人是根本无法读懂的,这样就实现了代码的保密性。

多人协作

test.h 头文件,里面包含函数的声明,#define定义宏,库函数所在的头文件,比如:

test.c放置函数的实现比如:

这种形式会在以后进行讲解。

生成静态库

6.2函数定义

函数定义就是实现函数的具体体现,交代了函数实现功能的细节。

七函数的递归

7.1递归的概念

在C语言中一个函数除了可以调用其他函数意外,还可以直接或间接的调用自己,这种函数自己调用自己的形式称为函数的递归调用。

7.2代码举例

下面通过练习来逐渐熟悉递归的使用。

  1. 接受一个整型值(无符号),按照顺序打印它的每一位。例如:

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

代码示例:

#include <stdio.h>
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int n = 0;
scanf("%d", &n);
print(n);
return 0;
}

这个代码的核心是:

1234要取到个位百位上的数时我们可以这样做:

1234%10 4

1234/10 123

123%10 3

123/10 12

12%10 2

12/10 1

1%10 1

这样就可以取出一个多位数字的每位数了。

关于递归,我们可以画图描述。

函数的递归顾名思义可以分为递推阶段和回归阶段。图中红色线代表递推阶段,蓝色线代表回归阶段。

  • 递推阶段。将原问题不断分解为新的子问题,,逐渐从未知向已知的方向推进,最终到达一直的条件,即递归结束条件,这时递推阶段结束。

  • 回归阶段。从已知条件出发,按照递推的逆过程,逐一求值回归,最终到达递推的开始处,结束回归阶段,完成递归调用。

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

解决问题的思路,函数递归,图解:

代码示例:

不允许使用临时变量,求字符串长度,也就是说不允许创建临时变量count
思路 使用函数递归的方式是实现
int my_strlen1(char* str)
{
    if (*str == '\0')
    {
        return 0;
    }
    else
    {
        return 1 + my_strlen1(str + 1);
    }
}
int main()
{
    char arr1[] = "hello world";
    printf("%d\n", my_strlen1(arr1));
    return 0;
}

7.3递归与迭代

循环是迭代的一种方式。

先做两个练习:

  1. 用递归求n的阶乘(不考虑异常)

这里可以使用一个公式:

当n <= 1时,n! = 1;当n > 1时,n! = n * factorial(n-1),这样我们就可以用递归的形式进行求解,

代码如下:

int factorial(int n)
{
    if (n <= 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}

int main()
{
    int n = 0;
    scanf("%d", &n);
    printf("%d", factorial(n));
    return 0;
}
  1. 求第n个斐波那契数

这里也可以使用公式:

当n<=2时,此时斐波那契数为1,当n>2时,斐波那契数为:fib(n-2)+fib(n-1),我们就可以用递归来求解,代码如下:

int fib(int n)
{
    if (n <= 2)
    {
        return 1;
    }
    else
    {
        return fib(n - 2) + fib(n - 1);
    }
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    printf("%d ", fib(n));
    return 0;
}

让我们来看一下,在求第40个斐波那契数时,第三个斐波那契数的计算次数。

我们只需要把函数修改成这样,定义一个全局变量count当n==3时count加1。

运行结果为:

可以看到,求第四十个斐波那契数时,计算第三个斐波那契数的次数为102334155,这样我们不得不担心一个问题,那就是栈溢出。我们都知道,函数在调用时,会在栈上实例化形参,这里调用了这么多次函数,虽然没有溢出,但是我们把n改为100呢,请看运行结果:

这里所耗费的时间会很长,最后程序会奔溃。stack overflow(栈溢出)

那么我们可以这样修改,这个代码。可以使用迭代的方式,分析:

当n <= 2时,return 1,当n > 2时 我们可以重复的执行 c = a+b, a = b, b = c 进行计算。

代码如下:

int fib1(int n)
{
    int a = 1;
    int b = 1;
    int c = 0;
    if (n <= 2)
    {
        return 1;
    }
    else
    {
        while (n > 2)
        {
            c = a + b;
            a = b;
            b = c;
            n--;
        }
    }
    return c;
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    printf("%d ", fib1(n));
    return 0;
}

运行结果:

函数板块完毕,这里给大家留两个关于函数递归的经典题目:

1、汉诺塔问题。
2、青蛙跳台阶问题。

结语:积跬步,行千里。天天学习,天天进步。祝我们未来都好。

感谢大家的捧场:这里是我的代码库,可以去里面找寻源代码。谢谢大家。

https://gitee.com/junpei-c-language

制作不易,点点赞小伙伴们。

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值