首页 > 其他分享 >函数和递归

函数和递归

时间:2023-01-03 11:37:30浏览次数:61  
标签:return 函数 递归 int ret printf include

  • 函数是什么
  • 库函数
  • 自定义函数
  • 函数参数
  • 函数调用
  • 函数的嵌套调用和链式访问
  • 函数的声明和定义
  • 函数递归

函数是什么?

维基百科定义:子程序

在计算机科学中,子程序是一个大型程序中的部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。

C语言中函数分类:

  1. 库函数
  2. 自定义函数


库函数

库函数学习工具:​​C语言库函数网站​​​,​​C参考手册​

常用库函数:

  • IO函数
  • 字符串操作函数
  • 字符操作函数
  • 内存操作函数
  • 时间/日期函数
  • 数学函数
  • 其他库函数

注:使用库函数,必须包含#include对应的头文件


自定义函数

自定义函数=返回值类型+函数名+函数参数

ret_type fun_name(para1, * )
{
statement;//语句项
}

ret_type - 返回值类型

fun_name - 函数名

para1 - 函数参数

例1:取最大值

#include <stdio.h>
//定义函数
int get_max(int x, int y)
{
if(x>y)
return x;
else
return y;
}

int main()
{
int a = 10;
int b = 20;
//函数的使用
int max = get_max(a, b);
printf("max = %d\n", max);
return 0;
}

例2:交换

#include <stdio.h>
void Swap(int x, int y)//void代表没有返回值
{
int tmp = 0;
tmp = x;
x = y;
y = tmp;
}

int main()
{
int a = 10;
int b = 20;
printf("a = %d b = %d\n", a, b);
Swap(a, b);
printf("a = %d b = %d\n", a, b);
return 0;
}
//输出结果:
//a = 10 b = 20
//a = 10 b = 20

以上代码并不能交换a和b的值,原因是x和y存储的位置与a和b并不相同,操作结果只是交换了x和y。

改进代码:运用取地址&,和解地址*

#include <stdio.h>
void Swap2(int* pa, int* pb)
{
int tmp = 0;
tmp = *pa;
*pa = *pb;
*pb = tmp;
}

int main()
{
int a = 10;
int b = 20;
printf("a = %d b = %d\n", a, b);
Swap2(&a, &b);
printf("a = %d b = %d\n", a, b);
return 0;
}
//输出结果:
//a = 10 b = 20
//a = 20 b = 10

函数参数

实际参数

真实传给函数的参数,叫实参。实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

形式参数

形参是指函数名后括号中的变量,形参只有在函数被调用的过程中才实例化(分配内存单元)。当函数调用完成之后形参就自动销毁了,因此形参只在函数中有效。

结论:形参其实是实参的一份临时拷贝,对形参的修改不会改变实参。


函数调用

传值调用

函数的形参和实参分别占用不同的内存块,对形参的修改不会影响实参。

传址调用

把函数外部创建变量的内存地址传递给函数参数,函数内部可以直接操作函数外部的变量。


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

嵌套调用

一个函数中调用了另一个函数。

例1:

#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;
}

链式访问

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

例1:

#include <stdio.h>
int main()
{
int len
//普通方式
len = strlen("abc");
printf("%d\n", len);
//链式访问
printf("%d\n", strlen("abc"));
return 0;
}

例2(易错):

#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
//输出结果是4321
//注:printf函数的返回值是打印函数的个数,返回值类型为int
printf("%d", printf("%d", printf("%d", 43)));//打印43,printf("%d", 43)返回2
printf("%d", printf("%d", 2));打印2,printf("%d", 2)返回1
printf("%d", 1);打印1

函数的声明和定义

函数声明

告诉编译器有这么一个函数(函数名、参数、返回类型),具体是否存在不一定

函数定义

函数具体的实现,交代函数的功能。

例1:

#include <stdio.h>
//函数声明
int Add(int x, int y);

int main()
{
int a = 10;
int b = 20;
int sum = 0;
//函数调用
sum = Add(a, b);
printf("%d\n", sum);
return 0;
}

//函数定义
int Add(int x, int y)
{
int z = x + y;
return z;
}
  • 如果函数定义写在函数调用前,则无需函数声明。
  • 实践中,函数声明写在头文件(如add.h)里,函数定义写在源文件(如add.c)里,函数调用前只需要在源文件(如test.c)中写上 #include"add.h"即可。


函数递归

​程序员的“知乎”​

递归的定义

程序调用自身的编程技巧称为递归。递归的主要思考方式在于“把大事化小”。

递归的两个必要条件

  1. 存在限制条件,满足限制条件时递归终止;
  2. 每次递归调用之后越来越接近限制条件。

例1:接受一个无符号整型值,按顺序打印它的每一位。如输入1234,输出1 2 3 4。

#include <stdio.h>
void print(int n)
{
if(n > 9)
{
print(n/10);
}
printf("%d", n%10);//%是mod取余的意思
}

int main()
{
unsigned int num = 0;
scanf("%d", &num);//输入1234
print(num);
return 0;
}

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

#include <stdio.h>
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);//arr是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
printf("len = %d\n", len);
return 0;
}

例3:求n的阶乘,不考虑溢出

#include <stdio.h>
int Fac1(int n)//循环的方式
{
int i = 0;
for(i=1; i<=n; i++)
{
ret *= i;
}
return 0;
}

int Fac2(int n)//递归的方式
{
if(n <= 1)
return 1;
else
return n*Fac2(n-1);
}

int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
ret = Fac1(n);//循环的方式
ret = Fac2(n);//递归的方式
printf("%d\n", ret);
return 0;
}

例4:求第n个斐波那契数,不考虑溢出

#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("ret = %d\n", ret);
return 0;
}

上述代码的缺点在于运行速度慢,而且有许多计算是重复的,这也是改进代码的突破口。

改进后:

#include <stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 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("ret = %d\n", ret);
return 0;
}
  • 当递归和循环都能解决问题的时候,选择简单的即可。
  • 递归容易出现“栈溢出”,此时改为用循环解决问题更合适。


标签:return,函数,递归,int,ret,printf,include
From: https://blog.51cto.com/u_15883132/5984783

相关文章