前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >C函数与递归

C函数与递归

原创
作者头像
WuShF
发布于 2023-03-07 15:05:51
发布于 2023-03-07 15:05:51
36200
代码可运行
举报
文章被收录于专栏:笔记分享笔记分享
运行总次数:0
代码可运行

函数的特性及定义

在编程语言中,可以把函数看做一个盒子,这个盒子有如下几个特性:

  • 开始执行时,函数可以被输入一些值
  • 执行过程中,函数可以做一些事情
  • 执行完成后,函数可以返回一些值

函数的写法公式:

代码语言:txt
AI代码解释
复制
函数返回值类型 函数名(函数输入参数值)
{
    做点什么事情
    return 函数返回值;
}

被花括号包括的被称为函数体,注意函数体一定要被花括号包括且不可省略。

花括号上面的函数名、函数参数及返回值被称作函数头

注意每个输入参数必须指明其变量类型,不能省略变量类型。

代码语言:txt
AI代码解释
复制
int add(int a, int b)   //正确
int add(int a, b)       //错误

函数的调用

函数需要被另一个函数调用才能执行。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int main()
{
	int result;
	result = add(2, 3); // 函数调用
	printf("%d", result);
	return 0;
}

main被称作主调函数,add被称作被调函数

在add函数头中,标明了函数的返回值类型为int,说明这个函数被调用后将返回一个int类型的结果

为什么要将代码封装成函数?

如果程序需要多次完成某项任务,那么你有两个选择:

  • 将同样的代码复制多份。
  • 将代码封装为一个函数,在需要的地方调用这个函数。

函数返回

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void showStarts()
{
	printf("    *\n");
	printf("   * *\n");
	printf("  * * *\n");
	printf(" * * * *\n");
	printf("* * * * *\n");
}
int main()
{
	showStarts();
	return 0;
}

showStarts 函数将会打印一个星星组成的三角形。这个函数没有输入参数,也不需要返回值。

所以,在函数定义时,参数的括号留空。返回值类型为 void ,表示空类型,即没有返回值。

可以在函数参数的括号中填上void,明确表示函数不需要参数。

可以用return将函数返回主调函数,并带回一个返回值。对于没有返回值的函数,可以省略return。函数运行完花括号内的语句后,就自动结束。

若函数需要返回值,则必须使用return带回一个返回值才能正常通过编译。

return可以出现在函数的任意位置。一旦程序执行到return,就会停止函数的执行,返回主调函数。

函数声明

在一个源文件中,如果函数调用前没有函数定义。那么可以使用函数声明通知编译器,有这个函数存在。

函数声明的写法非常简单:函数头 + 分号

函数声明也被称作函数原型

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <math.h>
// 函数调用前加上了函数声明,告诉编译器有这个函数存在
double areaOfTriangle(double a, double b, double c);
int isTriangle(double a, double b, double c);
int main()
{
	double a, b, c;
	scanf("%lf %lf %lf", &a, &b, &c);
	if (isTriangle(a, b, c) == 0)
	{
		printf("Not a triangle\n");
		return 0;
	}
	double s;
	s = areaOfTriangle(a, b, c);
	printf("area of triangle is %f", s);
	return 0;
}
// 函数定义放到了函数调用后
double areaOfTriangle(double a, double b, double c)
{
	double p, s;
	p = (a + b + c) / 2;
	s = sqrt(p * (p - a) * (p - b) * (p - c));
	return s;
}
int isTriangle(double a, double b, double c)
{
	if (a + b > c && a + c > b && b + c > a)
	{
		return 1;
	}
	return 0;
}

编译器读到函数声明后,便可知晓 areaOfTriangle 与 isTriangle 的参数与返回值。

在其后的函数调用中,可以根据函数声明的形式,检查参数类型和个数是否传递正确。返回值是否被正常接收。

虽然编译器暂时不知道函数里面是如何定义的,但是这对于检查函数调用是否正确已经足够了。

另外,函数声明时可以省略变量名。从这里可以看出,参数变量名对于函数声明来说并不重要,即使函数声明使用与函数定义不一样的参数变量名,也是可以的。

代码语言:txt
AI代码解释
复制
double areaOfTriangle(double a, double b, double c);
int isTriangle(double a, double b, double c);
// 省略参数变量名
double areaOfTriangle(double, double, double);
int isTriangle(double, double, double);
// 乱写参数变量名
double areaOfTriangle(double xsie, double sgrb, double xvdc);
int isTriangle(double aooj, double bngb, double vfhfc);

参数与返回值的类型自动转换

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int main()
{
	int result;
	result = add(2, 3); // 函数调用
	printf("%d", result);
	return 0;
}

add函数参数列表中的a,b被称作形式参数,简称形参。它指代函数参数的类型,以及参数进入add后,需要经历的处理步骤没有确定值

而在函数调用中add(2, 3)2,3被称作实际参数,简称实参。它们将确定形式参数的值具体是什么。

参数的自动转换

形式参数与实际参数的类型允许不一致的情况。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int main()
{
	int result;
	result = add(2.2, 3.3); // 函数调用
	printf("%d", result);
	return 0;
}

编译出现了两个警告,告诉我们double到int的转换会丢失数据,并且最后的结果为5。

将实际参数 2.2,3.3 传递给形式参数 int a, int b 时,编译器会尝试将实参转换为形参的类型。

若可以转换,那么将编译通过。若转换过程中可能出现数据丢失,将以警告的形式告诉程序员。 2.2,3.3 被转换为了整型 2,3 ,小数部分被丢失。

若无法转换,那么编译失败。

返回值的自动转换

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
double add(int a, int b)
{
	return a + b;
}
int main()
{
	double result;
	result = add(2, 3); // 函数调用
	printf("%f", result);
	return 0;
}

现在我们把返回值改为了double类型。但是,参数仍然保持int类型。

a与b相加的结果为int类型,返回时,会尝试将int转换为double。int可以被转换为double,所以编译通

过。

形参与实参相互独立

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}
int main()
{
	int a, b;
	int temp;
	a = 1;
	b = 2;
	printf("a=%d b=%d\n", a, b);
	// 交换a,b变量
	swap(a, b);
	printf("a=%d b=%d\n", a, b);
	return 0;
}

交换失败

代码语言:txt
AI代码解释
复制
a=1 b=2
a=1 b=2

虽然主函数中的变量a,b与函数中的形式参数a,b变量名相同。但是,它们却是相互独立的变量。

调用 swap 函数并传参时,是将主函数中变量a,b的值,传递给形式参数a,b。

不同函数内的变量相互独立

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void func()
{
	int a;
	a = 100;
	printf("a in func %d\n", a);
}
int main()
{
	int a = 0;
	printf("a in main %d\n", a);
	func();
	printf("a in main %d\n", a);
	return 0;
}

从结果中可以看出,这两个变量虽然变量名相同,但是却是两个互相独立的变量。

代码语言:txt
AI代码解释
复制
a in main 0
a in func 100
a in main 0

若去掉 func 函数中的变量声明,那么编译器将无法识别a标识符。

函数内声明的变量为局部变量,不同函数内的局部变量相互独立。

如果你想让一个局部变量的值在另一个函数中使用,可以把它当做一个参数,传递其值到另一个函数中。

函数递归调用

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void func(int n)
{
    printf("%d\n", n);
    func(n + 1);
}
int main()
{
    func(0);
    return 0;
}

编译可以通过,运行依次打印出了0,1,2,3,4,5......

在C语言中,在一个函数内部是可以再次调用自己的。这种调用被称之为函数递归

由于函数func首尾相接,它将造成程序陷入死循环。就像一条蛇,咬住了自己的尾巴,整个蛇构成了一个环形。

如果程序陷入了循环,请使用Ctrl + C组合键结束程序

如果不打断程序执行,那么过不了多久,程序将出现栈溢出异常,导致程序异常结束。

如何正确地进行递归?

递归函数的两个要素:

  • 递推规则
  • 递推结束条件

现在我们给程序加上递推结束条件,当n为5时,就让递推结束。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void func(int n)
{
    if (n == 5)
        return;
    printf("%d\n", n);
    func(n + 1);
}
int main()
{
    func(0);
    return 0;
}

流程在n小于5之前,一直递推至下级函数。当n为5时,从下级函数开始回归

递推与回归

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void func(int n)
{
    if (n == 5)
        return;
    printf("after %d\n", n);
    func(n + 1);
    printf("before %d\n", n);
}
int main()
{
    func(0);
    return 0;
}

输出结果

代码语言:txt
AI代码解释
复制
after 0
after 1
after 2
after 3
after 4
before 4
before 3
before 2
before 1
before 0

标号为1,2,3,4,5的printf在递推过程中,被依次执行。而标号为6,7,8,9,10的printf,必须等到回归过程,才会被执行到。由于回归过程与递推过程是逆向的,所以,输出的n值是逆序的。

对于此func函数,放在递归调用前的语句将在递推过程中执行。而放在递归调用后的语句将在回归过程中执行。

使用递归计算阶乘

规律如下:

  • 当n为1或0时,n的阶乘为1。
  • 当n大于1时,n的阶乘为n * (n - 1)!

那么假设有这么一个函数f(n),这个函数传入一个整数n,返回n的阶乘n!。

  • 当n为1或0时,f(n)返回1。
  • 当n大于1时,f(n) = n * f(n - 1)

写出如下代码。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int f(int n)
{
    if (n == 0 || n == 1)
    {
        return 1;
    }
    return n * f(n - 1);
}
int main()
{
    int result = f(4);
    printf("%d\n", result);
    return 0;
}

递推流程中,可以确定当前的n分别为4,3,2,1。

接着进入了递归调用f(n - 1),直到n为1时,开始回归。

回归到n为2时,计算2 * 1。

回归到n为3时,计算3 (2 1)。

回归到n为4时,计算4 (3 2 * 1)。

使用递归计算斐波那契数列

斐波那契数列,第1、2项分别为1,之后每一项为前两项相加之和

那么假设有这么一个函数f(n),这个函数传入一个整数n,返回斐波那契数列的第n项。

  • 当n为1或2时,f(n)返回1。
  • 当n大于2时,f(n) = f(n - 1) + f(n - 2)。
代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int f(int n)
{
    if (n == 1 || n == 2)
    {
        return 1;
    }
    return f(n - 1) + f(n - 2);
}
int main()
{
    int result = f(4);
    printf("%d\n", result);
    return 0;
}

上图中,红线为递推过程,蓝线为回归过程。

当表达式f(n-1)+f(n-2)中,两个函数均回归了结果,即可计算和,再回归上级。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
c语言基础知识帮助理解(详解函数)
函数是一段可以执行特定任务的代码块。它可以接受输入参数并返回一个值。函数使得代码可以被模块化,重复使用,并提高代码的可读性和可维护性
是Nero哦
2024/01/18
1520
c语言基础知识帮助理解(详解函数)
函数
在定义的函数的时候,如果在函数定义前调用,需要在调用的前面加上一个函数声明 告知这个函数存在
DeROy
2020/05/11
3720
C语言学习——函数(含递归)
(1) 一个源文件由一个或者多个函数组成。 (2) 一个C程序由一个或者多个源文件组成。 (3) C程序的执行从 main 函数开始。 (4) 所有的子函数都是平行的。 (5) 从用户的角度看,函数分库函数和自定义函数。 (6) 函数形式: ①无参函数:主调函数无数据传送给被调函数,可带或不带返回值。 ②有参函数:主调函数与被调函数间有参数传递,主调函数可将实参传送给被调函数的形参, 被调函数的数据可返回主调函数。
全栈程序员站长
2022/09/23
7370
C语言学习——函数(含递归)
C语言的函数
1.我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格式打印到屏幕上(printf)。
绝活蛋炒饭
2024/12/16
830
C语言的函数
【c语言】函数
“函数”早已是我们在数学中常见的概念了。在数学当中,给定一个x的值,可以对应求出y值。在c语言中,也有“函数”的概念,它就是一个完成某些特定功能的代码。实际上,c语言程序就是由一个个函数组成的,我们最常使用的main函数也是函数。
ephemerals__
2024/10/24
1230
【c语言】函数
函数的说明与使用
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method,
用户10921393
2024/01/23
1740
函数的说明与使用
C语言笔记(8)函数篇
返回值必须记录在被调用函数的储存区里,编写函数的时候要把这个储存区的类型名称卸载函数名称前面
是小北a
2024/08/23
1260
C语言笔记(8)函数篇
C语言——函数
C语言中的函数又常常被称为子程序,是用来完成某项特定的工作的一段代码。就像我们生活中的模块化建造技术,类比模块化建房子的过程:整个程序好比最终要建成的房子,而函数所代表的就是每部分模块(如第一层,第二层或者屋顶···),将这些模块灵活的拼接,就搭建成了最后的房子。
用户11029137
2024/03/19
1110
C语言——函数
C语言——函数(2)
在前面,我们学习一些函数的一些基础知识。接下来我们进一步的来深入理解函数并且进行一些应用。
用户11352420
2024/11/07
660
C语言——函数(2)
C语言——E/函数
⼀个⼤的计算任务可以分解成若干个较小的函数(对应较小的任务)完成。同时⼀个函数如果能完成某项特定任务的话,这个函数也是可以重复用的,提升了开发软件的效率。
用户11015888
2024/03/11
1080
C语言——E/函数
C语言函数:编程世界的魔法钥匙(1)-学习笔记
本文全篇近一万字,由于大多数是小编手敲的,因此可能会有些错误的地方,各位大佬可以在评论区指正,万分感谢!!
LonlyMay
2024/10/21
930
C语言函数:编程世界的魔法钥匙(1)-学习笔记
函数类的学习
函数学习库函数www.cplusplus.comwww.cppreference.com//从这两个网站可搜索所有的库函数,是一个查询工具IO函数字符串操作函数内存操作函数时间/日期函数数学函数其它库函数//内存操作函数memory set = memsetmemset(void*ptr,int value,size_t num);//把ptr所指向的空间的前num个字节的内容设置成指定的value这个值//例#include<stdio.h>#include<string.h>int main(){
暮云
2022/10/16
3150
c语言之函数的本质和使用及递归函数
从今天开始,给大家分享c语言里面的函数本质及其使用;我估计大多读者看到这个,都认为c语言函数里面有啥可讲的,其实在学习过程中千万不要小看每一个知识点,因为每一个小的知识点都是给你在做项目之前打牢基础,很多人肯定会遇到过这种情况,在做项目写代码的时候,诶!用什么方法才能实现我要的功能以及这种写法怎样表示,甚至一些基础的语法错误都会有(严重的话,一些最为基本的错误都解决不了,发现不了。),归根到底还是基础不牢,其实这样做起项目来比较痛苦的(不过这会让你注视到c语言功底的重要性了)。好了,废话就不多说了,开始今天的主题分享!
用户6280468
2022/03/21
7540
C语言函数基础知识详解
数学中我们其实就见过函数的概念,比如:一次函数 y=kx+b ,k和b都是常数,给一个任意的x,就得到一个y值。
fhvyxyci
2024/09/24
1140
C语言函数基础知识详解
函数(2)
再举一个简单的例子:假设有一位程序员写了一个能够求两数相加之和的函数,他想卖给别人使用,但又不想让别人看到他的源代码,他应该怎么做呢?
waves浪游
2024/01/23
1690
函数(2)
【C 语言篇】形参实参密钥与递归魔法之门:C 语言编程中开启算法奥秘的奇妙旅程
编程中,形参是函数定义时的占位符,实参是调用时传递的具体值。递归通过函数自我调用解决问题,理解它们的关系有助于写出高效、健壮的代码。 本文我们主要来介绍形参 实参 和递归
意疏
2024/12/26
1100
函数部分的详细讲解
在数学里,我们经常接触并且为之头疼的就是函数,但是越头疼,反而用到的越多,数学中不开函数。同样在C语言里,也存在着函数。 在C语言里,函数是一个完成特定工作的独立程序模块,包括库函数和自定义函数两种。
诺诺的包包
2023/02/17
3800
函数部分的详细讲解
【C语言基础】:函数详解
C语言是一种面向过程的编程语言,函数是C语言中的基本概念之一。C语言中的函数是一段被命名的、可重复利用的代码块,用于执行特定的任务或操作。函数使程序模块化,提高了代码的可读性和维护性。它封装了一系列的操作或任务,并可以通过函数名进行调用和执行。
爱喝兽奶的熊孩子
2024/04/10
2190
【C语言基础】:函数详解
c语言基础学习06_函数
============================================================================= 涉及到的知识点有:1、C语言库函数、字符输入函数:gets和fgets、字符输出函数:puts和fputs、 求字符串长度函数strlen、字符串追加函数strcat、字符串有限追加函数strncat、字符串比较函数strcmp、 字符串有限比较函数strcmp、字符串拷贝函数strcpy、字符串有限拷贝函数strncpy、 格式化字符串函数sprintf(输出)、格式化字符串函数sscanf(读取输入)、解析一个字符串、 字符串查找字符函数strchr、字符串查找子串函数strstr、字符串分割函数strtok、 atoi函数、atof函数、atol函数、解析一个字符串的高级应用。 2、函数的定义和声明、函数的形式参数(形参)与实际参数(实参)、函数的返回值类型和返回值、 return函数与exit函数(exit更猛,不受位置限制)、自定义一个函数,实现大小写字母的互相转换功能、 自定义一个函数,实现atoi的功能。 3、函数的递归、递归例子:有n个人排成一队、递归例子:将10进制数转化为二进制数、 递归例子:将10进制数转化为16进制、递归例子:菲波那切数列、递归的优点与缺点。 4、多个源代码文件程序如何编译、头文件的使用、解决预编译时会出现多次函数声明问题。 ============================================================================= C语言库函数
黑泽君
2018/10/11
1.3K0
【C语言】函数超详解总结
数学中我们其实就见过函数的概念,比如:一次函数 y=kx+b ,k和b都是常数,给一个任意的x,就得到一个y值。
用户11290673
2024/09/25
1140
【C语言】函数超详解总结
相关推荐
c语言基础知识帮助理解(详解函数)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文