自学内容网 自学内容网

【C 语言篇】形参实参密钥与递归魔法之门:C 语言编程中开启算法奥秘的奇妙旅程


【C 语言篇】形参实参密钥与递归魔法之门:C 语言编程中开启算法奥秘的奇妙旅程

💬欢迎交流:在学习过程中如果你有任何疑问或想法,欢迎在评论区留言,我们可以共同探讨学习的内容。你的支持是我持续创作的动力!
👍点赞、收藏与推荐:如果你觉得这篇文章对你有所帮助,请不要忘记点赞、收藏,并分享给更多的小伙伴!你们的鼓励是我不断进步的源泉!
🚀推广给更多人:如果你认为这篇文章对你有帮助,欢迎分享给更多对编程感兴趣的朋友,让我们一起进步,共同提升!

前言

编程中,形参是函数定义时的占位符,实参是调用时传递的具体值。递归通过函数自我调用解决问题,理解它们的关系有助于写出高效、健壮的代码。
本文我们主要来介绍形参 实参 和递归

一 、参数传递

1. 调用函数
  • 如果函数有参数,调用函数时必须传递给他数量、类型正确的值。
  • 可以传递给函数的值是表达式的结果 包括:
    • 字面量
    • 变量
    • 函数的返回值
    • 计算的结果

但是这很可能类型不匹配

  • 调用函数时给的值与参数的类型不匹配是C语言一个非常大的漏洞
  • 编译器总是悄悄转换好类型,但是这很可能不是你自己所期望的。

例如:

#include <stdio.h>
void cheer(int i)
{
printf("cheer %d\n", i );
}
int main()
{
   cheer(2.4);
   
   return 0;
}

输出结果:
cheer 2

  • 这里可能会弹出一个警告 但是输出为2
2. 数值传递
void swap(int a, int b)//形式参数 ;
int main()
{
    int a = 5;
    int b = 6;
    swap(a,b);//实际参数
    printf("a=%d\n b=%d\n", a, b);
    return 0;
}

C语言在调用函数时 永远只能传值给函数

  • 每个函数都会有自己的变量空间,参数也位于这个独立的空间中,与其他函数没有关系。
  • 函数参数列表中的函数 叫做形式参数 调用函数所用的值 叫做实际参数

接下来 我们详细来看

二 、带参数或返回值的函数

1. 带有参数的函数

首先我们来举个例子,假设我们需要求10到20的和:

#include <stdio.h>
void sum()
{
    int num1 = 10;
    int num2 = 20;
    int sum = num1 + num2;
    printf("%d\n",sum);
}
int main(){
    sum();
    return 0;
}

我们可以很轻松地得到输出结果:

30

可是如果我们改一下题目,要求20到30的和,或者30到40的和,就会特别麻烦,因为要一直修改num1num2的值。

这个问题的本质原因在于,代码中的加法操作涉及的数字是固定的。在实际编程中,我们希望代码能够灵活处理不同的输入值。为了解决这个问题,我们可以将num1num2定义为函数的参数。

void sum(int num1, int num2)  //这里仅定义,未赋值

那么我们应该如何调用这个函数呢?这时就需要在调用时传入具体的数值:

#include <stdio.h>
void sum(int num1, int num2)
{
    int sum = num1 + num2;
    printf("%d\n",sum);
}
int main(){
    sum(10, 20);  //在这里传入实际的值
    return 0;
}

这样,我们就可以更灵活地得到输出结果:

30
  • 总而言之,当函数需要计算的参数不明确时,我们就可以将参数定义在小括号中:
void sum(int num1, int num2)  //这里只是定义了参数

在调用函数时,我们根据需要传入不同的实际参数:

函数名(参数1, 参数2, ....)

虽然num1num2在函数中都被称为“参数”,但是它们实际上有不同的作用与含义:

  • 形参(形式参数):是函数定义时,在小括号中声明的变量,它们用于接收函数调用时传入的值。例如:int num1, int num2
  • 实参(实际参数):是函数调用时,传入函数的具体值或变量。例如:sum(10, 20)中的1020

形参与实参必须一一对应,即在函数定义时声明的参数和调用时传入的参数数量、类型需一致。

通过这种方式,函数能够灵活地处理不同的输入数据,从而提高代码的通用性和复用性。

2. 带有返回值的函数

在C语言中,函数不仅可以执行操作,还可以返回结果。带有返回值的函数通过return语句返回一个值给调用者。返回值可以是任何有效的数据类型,如int、float、char等。函数的返回类型需要在函数定义时声明。

void sum(int num1,int num2)
{
int sum = num1 + num2;
printf("%d\n",sum);
}

其实上面这篇代码还有一点点缺陷 我们来继续往下看

int main(){
    sum(10,20);
    return 0;
}

我们其实可以看到 上面并没有把最终的结果交给调用者 而是说直接打印在了控制台上,调用者拿不到最终结果。如果我们遇到复杂的题目时,就不可以这么写了,这时我们就需要带返回值了。

  • 带返回值的函数格式:
返回值类型 函数名(形参1,形参2...)
{
函数体;
return返回值;//返回值要和上面的类型一致
}

调用方式:

1. 变量 = 函数名(实参)
2. printf("占位符",函数名(实参))

题目:计算小明考试成绩基础分90 附加题得分5分 小红基础分85 附加题得分8分

#include <stdio.h>

int sum(int base, int additional) // 形参
{
    int sum = base + additional; // 局部变量
    return sum;                  // 返回函数调用者
}

int main() 
{
    int score1 = sum(90, 5);     // 小明的总成绩
    int score2 = sum(85, 8);     // 小红的总成绩
    if (score1 > score2) 
    {
        printf("小明的成绩优于小红\n");
    } else {
        printf("小红的成绩优于小明\n");
    }
    return 0;
}

输出结果:

小明的成绩优于小红
  • 总结

带返回值的函数:返回类型在函数定义时明确,返回结果通过return语句传递给调用者。
return语句:终止函数并返回结果,确保函数能够将计算结果传递给外部。
数据类型匹配:返回值的类型与函数声明的返回类型必须一致。
灵活性:带返回值的函数提高了代码的灵活性和复用性,且可用于处理更复杂的任务。

三 、递归

递归(Recursion)是指函数在其定义中直接或间接地调用自身。在C语言中,递归是一种强大的编程技巧,通常用于解决可以分解为类似子问题的任务。递归的关键是要有一个终止条件,防止函数无限调用自己,导致栈溢出。

1. 递归的主要部分

递归函数通常包含两个主要部分:

  1. 基本情况(Base Case):递归的终止条件。当满足某个条件时,函数不再递归调用自身,而是返回一个具体的值。
  2. 递归步骤(Recursive Case):函数调用自身,并传递不同的参数(通常是问题的一个简化版本)。
2. 递归函数的结构

递归函数通常遵循以下结构:

返回类型 函数名(参数)
{
    // 基本情况:如果满足终止条件,返回一个值,停止递归
    if (满足某个条件)
    {
        return 基本情况的结果;
    }
    
    // 递归步骤:调用自身,并传递修改后的参数
    else
    {
        return 函数名(修改后的参数);  // 递归调用
    }
}
3. 递归举例:阶乘

阶乘是一个经典的递归问题,定义如下:
n! = n * (n-1) * (n-2) * ... * 1
递归形式:

n! = n * (n-1)!
1! = 1 (基本情况)

代码示例:计算阶乘

#include <stdio.h>
// 递归函数计算阶乘
int factorial(int n)
{
    // 基本情况:当n等于1时,返回1
    if (n == 1)
    {
        return 1;
    }
    // 递归步骤:n * (n-1)!
    else
    {
        return n * factorial(n - 1);
    }
}
int main()
{
    int num = 5;
    int result = factorial(num);  // 调用递归函数
    printf("%d! = %d\n", num, result);  // 输出结果
    return 0;
}

输出结果:

5! = 120
4. 递归的工作原理

factorial(5)为例,递归调用过程如下:

  • factorial(5) 调用 factorial(4),然后返回 5 * factorial(4)
  • factorial(4) 调用 factorial(3),然后返回 4 * factorial(3)
  • factorial(3) 调用 factorial(2),然后返回 3 * factorial(2)
  • factorial(2) 调用 factorial(1),然后返回 2 * factorial(1)
  • factorial(1) 返回 1(基本情况)

递归开始“展开”,依次返回每一层的计算结果,最终返回 120

5. 递归的优点和缺点

递归的优点

  • 简洁:递归能够以简洁的代码解决复杂的数学问题和算法(如斐波那契数列、排序算法等)。
  • 易于理解:递归适用于问题能够自然分解为子问题的场景。

递归的缺点:

  • 性能问题:递归会消耗较多的栈空间,特别是递归深度较大时,容易导致栈溢出。
  • 效率低下:对于某些递归问题,如果没有适当的优化(如记忆化递归),可能会导致重复计算,性能较低。
6. 递归的优化:尾递归

尾递归是一种优化递归方式,要求递归调用是函数的最后一步操作。尾递归可以被编译器优化为迭代,从而避免不必要的栈帧开销。

例如,尾递归形式的阶乘计算可以这样实现:

#include <stdio.h>

// 尾递归计算阶乘
int factorial_tail_recursive(int n, int accumulator)
{
    if (n == 1)
    {
        return accumulator;
    }
    else
    {
        return factorial_tail_recursive(n - 1, n * accumulator);
    }
}

int main()
{
    int num = 5;
    int result = factorial_tail_recursive(num, 1);  // 从1开始递归
    printf("%d! = %d\n", num, result);  // 输出结果
    return 0;
}

在这种实现中,accumulator参数用于保存中间结果,从而避免递归调用时每次都重新计算。

递归常见应用

  • 数学问题:如阶乘、斐波那契数列、组合数等。
  • 树和图的遍历:递归在树的深度优先遍历、图的深度优先搜索中非常常见。
  • 分治算法:许多分治算法(如快速排序、归并排序)都依赖递归。
7.关于递归的总结
  • 递归是函数调用自身的过程,通常用于解决可以分解成更小子问题的问题。
  • 递归需要确保有一个基本情况来终止递归,否则会导致栈溢出。
  • 递归有时会因为栈空间的限制导致效率低下,可以通过尾递归优化减少空间开销。
  • 递归适用于自然分解为子问题的场景,但对于一些问题,也可以考虑使用迭代方式来避免递归的潜在问题。

结语

在 C 语言中,形参实参递归是重要的概念,理解它们能够帮助我们更高效地编写程序。

  • 形参(形式参数)是在函数定义中声明的参数,用于接收调用者传递的值。形参是局部变量,作用域仅限于函数内部,函数调用时被赋值,用于进行逻辑操作或计算处理。

  • 实参(实际参数)是在函数调用中传递给形参的实际值。实参可以是常量、变量或表达式,调用时将其值或地址(取决于传递方式)传递给函数中的形参。

  • 递归是函数调用自身的一种编程技术,用于解决问题的分解和归纳。递归函数需要明确终止条件,以防止无限循环。递归分为直接递归间接递归,在复杂问题中非常有效,但可能导致较高的空间消耗。

通过合理使用形参、实参和递归,可以实现灵活、可复用的程序设计,提高代码的效率与可维护性。

那么我想以上这就是【C 语言篇】形参实参密钥与递归魔法之门:C 语言编程中开启算法奥秘的奇妙旅程的内容了,通过对形参实参递归的学习,使我们可以在编程中更好的解决问题。❤️
在这里插入图片描述


意气风发,漫卷疏狂
学习是成长的阶梯,每一次的积累都将成为未来的助力。我希望通过持续的学习,不断汲取新知识,来改变自己的命运,并将成长的过程记录在我的博客中
如果我的博客能给您带来启发,如果您喜欢我的博客内容,请不吝点赞、评论和收藏,也欢迎您关注我的博客。
您的支持是我前行的动力。听说点赞会增加自己的运气,希望您每一天都能充满活力!

愿您每一天都快乐,也欢迎您常来我的博客。我叫意疏,希望我们一起成长,共同进步。
logo 我是意疏 下次见!


原文地址:https://blog.csdn.net/2302_79751907/article/details/144517737

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!