递归
1.什么是递归?
递归就是函数或过程在其定义或声明的中有直接或间接调用自身的一种方式。他通常将一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
2.递归的主要思想:大事化小
求第n个斐波那契数(不考虑溢出)
int fib(int n)
{
if (n <= 2)
return 1;
return fib(n-1) + fib(n - 2);
}
求n的阶乘:
int factorial(int n)
{
if (n <= 1)
return 1;
else
return n*factorial(n - 1);
}
不允许建立临时变量,求字符串长度
int my_strlen(char* str)
{
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
3.递归的俩个必要条件
- 存在限制条件,当满足这个限制条件的时候,递归便不在继续(递归要有出口)
- 每次递归之后越来越接近这个限制条件
4.递归的缺点
- 系统分配给程序的栈空间是有限的,单数如果出现了死循环,死递归等问题,就可能导致一直开辟空间,最终产生栈空间耗尽的情况,这样的现象我们叫做栈溢出
- 递归虽然使程序的可读性强,思维逻辑更清晰,但其效率低
5.如何解决上述问题:
- 将程序由递归改为非递归
- 在递归内部使用static(栈对象)对象代替非static局部变量(栈对象),这样就不用频繁的去申请和释放栈空间
- 建议使用第一种方法
可变参数列表
c语言可以通过可变参数列表来实现一个函数,使得函数可以接受一个以上任意多个参数(不固定)
- 在函数定义的时候参数列表至少明确的定义一个参数,其余的可变参数列表用...表示
实现一个求平均数的函数,给的任意的数字,求他们的平均数
int average(int n, ...)
{
va_list arg;
int i = 0;
int sum = 0;
va_start(arg, n);
for (i = 0; i < n; i++)
{
sum = sum + va_arg(arg, int);
}
return sum / n;
va_end(arg);
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int vag1 = average(2, a, c);
int vag2 = average(3, a, b, c);
printf("vag1 = %d\n", vag1);
printf("vag2 = %d\n", vag2);
system("pause");
return 0;
}
//用n表示接收参数的个数,...表示可变参数列表
- 可变参数列表要通过四个宏来辅助完成
1)这四个宏的头文件#include<stdarg.h>
2) va_list,用来声明一个变量,变量的类型为va_list,他用于访问参数列表未确定的部分
3)这个变量是调用va_start来初始化的,va_start(arg,n)他的第一个参数是va_list的变量名,第二个参数是省略号前最后一个有名字的参数,初始化过程把arg变量设置为指向可变参数部分的第一个参数。
4)为了访问参数,需使用va_arg,这个宏接受俩个参数,va_list变量和参数列表中下一个参数的类型
5)最后,当访问完最后一个可变参数之后,我们需要调用va_end,将指针置空。
- 注意事项:
1)参数列表必须从头到尾逐个访问,如果你访问了几个就想终止,或者是一开始就绪从中间访问,都是不行的。
2)这些宏都没有办法检查参数类型,如果在使用va_arg时指错了参数类型,后果不堪设想
3)这些宏无法直接判断实际存在参数的数量
可变参数的实现过程其实就是使用这些宏来辅助完成的