第36课 - 函数递归与函数设计技巧
一. 递归
- 递归概述
(1) 递归是数学领域中的概念在程序设计中的应用。
(2) 递归是一种强有力的程序设计的方法。
(3) 递归的本质为函数内部在适当的时候调用自身。
- 组成部分
(1)递归点:以不同参数调用自身。
(2)出口:不在递归调用
下面就是求一个数的阶乘的函数:
#include <stdio.h>
int func(int x)
{
if( x > 1 )
{
return x * func(x - 1); //递归点
}
else
{
return 1; //出口
}
}
int main()
{
printf("x! = %d ", func(4));
return 0;
}
运行结果:4!= 24
虽说调用了一次,却创建了4次活动记录。所以说我们的递归函数不能递归太多的层次。
小结:
C语言中的递归函数必然会使用判断语句。
递归函数在需要编写的时候定义函数的出口,否则栈会溢出。
递归函数是一种分而治之的思想。
思考题:编写一个函数打印一个字符数组的全排列。
void Permutation(char *pStr,char *pBegin)
{
assert(pStr&&pBegin);
if(*pBegin == ' ')
printf("%s
",pStr);
else
{
for(char *pCh=pBegin; *pCh !=' '; pCh++)
{
char temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
Permutation(pStr, pBegin+1);
temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
}
}
}
二. 函数的设计技巧
- 不要在函数中使用全局变量,尽量让函数从意义上是一个独立的功能模块。
- 参数名要能够体现参数的意义。
void str_copy(char *str1, char *str2);
void str_copy(char *str_dest, char *str_src);
- 如果函数是指针,且仅作为输入参数用,则应在类型前加const,以防止该指针在函数体内被意外修改。
void str_copy(char *str_dest, const char *str_src);
- 不要省略返回值的类型,如果函数没有返回值,那么应该声明为void类型。
- 在函数体的“入口处”,对参数的有效性进行检查,对指针的检查尤为重要。
- 语句不可返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁。
- 函数体的规模小,尽量要控制在80行代码之内。
- 相同的输入应当产生相同的输出,尽量避免函数带有“记忆”功能。
- 避免函数有太多的参数,参数的个数尽量控制在4个以内。
- 有时候函数不需要返回值,但是为了增加灵活性,加支持链式表达,可以附加返回值:
char s[64];
int len = strlen(strcpy(s,”android”));
- 函数名与返回值类型在语义上不可以冲突
char c;
c = getchar(); //getchar的返回值是int不是char。
if(EOF==c) //会出错,永远不会进入。
{ //... }