四.函数(2)

本文介绍了C语言中函数的嵌套调用和链式访问的概念,通过示例展示了如何在一个函数内部调用其他函数以及如何将函数返回值传递给另一个函数。接着讨论了函数的声明和定义,强调了先声明后使用的规则,并提到了头文件的使用。此外,文章还详细解释了递归的概念,包括递归的必要条件和递归函数的应用,如计算字符串长度和斐波那契数列,同时也对比了递归和迭代在解决问题时的效率差异。
摘要由CSDN通过智能技术生成

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

函数和函数之间可以有机结合的

嵌套调用

C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能再定义另一个函数,即不能嵌套定义,但可以嵌套调用函数。即在调用一个函数的过程中,又调用另一个函数

#include <stdio.h>
void new_line()
{
    printf("hehe\n");
}
void three_line()
{
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        new_line();//在一个函数中调用另一个函数
    }
}
int main()
{
    three_line();
        return 0;
}

运行结果:

hehe

hehe

hehe

-- -- -- -- -- -- -- -- -- --

链式访问

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

#include <stdio.h>
#include <string.h>
int main()
{
    int len = 0;
    printf("%d\n", strlen("abc"));//strlen函数的返回值是字符串的长度
    return 0;
}

运行结果:3

再来一个例子:

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

运行结果:4321

printf()函数的返回值是打印在屏幕上字符的个数

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

7.函数的声明和定义

函数声明

  1. 告诉编译器有一个函数叫什么、参数是什么、返回类型是什么。但是具体这个函数有没有存在,无关紧要

  1. 函数的声明一般出现在函数的使用之前,要满足先声明后使用

  1. 函数的声明一般要放在头文件

-- -- -- -- -- -- -- -- -- --

函数定义

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

#include <stdio.h>
int Add(int x, int y);//函数声明
int main()
{
    int a = 0;
    int b = 0;
    int sum = 0;
    sum = Add(a, b);
    printf("%d\n", sum);
    return 0;
}
int Add(int x, int y)//函数定义
{
    return x + y;
}
  • 实际上不会这样去使用。应该自己创建一个头文件,把函数声明放在头文件(add.h)中,把函数定义放在另一个源文件中。若需要使用函数,再main函数所在源文件引用头文件即可,如:#include "add.h"(要使用双引号进行引用)

  • 若把函数定义在主函数之前则不声明函数也行

-- -- -- -- -- -- -- -- -- --

在自己创建头文件中:

#ifndef __ADD_H__//如果没有定义add.h
//ifndef————if not define————为了防止多次的被引用
//防止add.h被重复引用 
#define __ADD_H__//那就引入add.h

//...函数声明

#endif // !__ADD_H__
//否则不需要引入

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

8.函数递归

什么是递归

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

-- -- -- -- -- -- -- -- -- --

递归的两个必要条件

  • 存在限制条件时,当满足这个限制条件,递归便不在继续

  • 每次递归调用之后越来越接近这个限制条件

-- -- -- -- -- -- -- -- -- --

示例

#include <stdio.h>
int main()
{
    printf("hehe\n");
    main();//在主函数中调用主函数
    return 0;
}

运行结果:

hehe

hehe

...

(无限打印hehe)

一段时间后报错并弹出stack overflow(栈溢出)

  • 没调用一次函数就会在栈区开辟并占用一块空间,栈区空间被耗干时就会弹出stack overflow

  • 内存

-- -- -- -- -- -- -- -- -- --

练习

接收一个整型值(无符号),按照顺序打印它的每一位。例如输入6941,输出6 9 1 4

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

运行结果:6 9 1 4

-- -- -- -- -- --

编写一个函数不允许创建临时变量,求字符串长度(模拟实现strlen)

创建临时变量

#include <stdio.h>
int my_strlen(char* str ) //int my_strlen(char str[])一样的
{
    int count = 0;//创建临时变量
    while (*str != '\0')
    {
        count++;
        str++;//指针+1.让“b”和地址编程“t”的地址
    }
    return count;
}
int main()
{
    char arr[] = "bit";
    int len = my_strlen(arr);
    printf("len=%d\n",len);
    return 0;
}

运行结果:len=3

不创建临时变量

#include <stdio.h>
//用递归的方法,大事化小
//思路:
//my_strlen("bit");
//1+my_strlen("it");
//1+1+my_strlen("t");
//1+1+1+my_strlen("");
//1+1+1+0
int my_strlen(char* str)
{
    if (*str != '\0')
    {
        return 1 + my_strlen(str + 1);
    }
    else
    {
        return 0;
    }
}
int main()
{
    char arr[] = "bit";
    int len = my_strlen(arr);
    printf("len=%d\n", len);
    return 0;
}

运行结果:len=3

  • 第十三行的return 1 + my_strlen(str + 1);是为了获得下一个地址

  • 在从b → i → t → '\0'的过程中,if的条件判断为假,走else

  • 即开始return 0;(返回上一个函数的位置)

  • my_strlen b:返回1+1+1+0

  • ⬇ ⬆

  • my_strlen i: 返回1+1+0

  • ⬇ ⬆

  • my_strlen t: 返回1+0

  • ⬇ ⬆

  • my_strlen '\0': 返回0

-- -- -- -- -- -- -- -- -- --

递归与迭代

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

递归
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Fac1(int n)
{
    if (n <= 1)
    {
        return 1;
    }
    else
    {
        return n * Fac(n - 1);
    }
}
int main()
{
    int n = 0;
    int ret = 0;
    scanf("%d", &n);
    ret = Fac(n);
    printf("%d\n", ret);
    return 0;
}

运行结果:

输入:6

输出:720

-- -- -- -- -- --

迭代(循环)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Fac2(int n)
{
    int i = 0;
    int ret = 1;
    for (i = 1; i <= n; i++)
    {
        ret *= i;
    }
    return ret;
}
int main()
{
    int n = 0;
    int ret = 0;
    scanf("%d", &n);
    ret = Fac2(n);
    printf("%d\n", ret);
    return 0;
}

-- -- -- -- -- -- -- -- -- --

练习:计算第n个斐波那契数

递归
#define _CRT_SECURE_NO_WARNINGS
#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;
    int ret = 0;
    scanf("%d", &n);
    ret = Fib(n);
    printf("%d\n", ret);
    return 0;
}

运行结果:

输入5,打印5

输入10,打印55

输入50,很长时间都不会弹出结果,计算机在不停的计算(不考虑溢出)

  • 50

  • 49 48

  • 48 47 47 46

  • 47 46 46 45 46 45 45 44

  • ...可见计算了非常多相同的数且计算量大到恐怖

  • 因此不适合使用递归

  • 使用循环来解决(迭代)

-- -- -- -- -- --

迭代
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Fib(int n)
{
    int a = 1;
    int b = 1;//前两个数都是1
    int c = 1;//如果输入的n小于2,便于直接返回1
    while (n > 2)
    {
        c = a + b;
        a = b;
        b = c;
        n--;
    }
    return c;
}
int main()
{
    int n = 0;
    int ret = 0;
    scanf("%d", &n);
    ret = Fib(n);
    printf("%d\n", ret);
    return 0;
}

运行结果:

输入5,打印5

输入10,打印55

输入50,打印-298632863(瞬间弹出结果,不管对不对但是非常快;早就溢出了)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世长老

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值