函数声明
1. 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数
声明决定不了。
2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用。
3. 函数的声明一般要放在头文件中的。
函数定义
函数的定义是指函数的具体实现,交待函数的功能实现。
函数的递归
一个过程或函数在定义或说明中有直接或间接调用其本身的一种方法,通常可以把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归可以简化减少程序代码数量,但也可能会加大运算量。
递归的两个必要条件
1.递归需存在限制条件,当满足条件时,递归便不再继续,不能使递归无限制地进行下去,否则会造成死循环和栈溢出。
2.随着递归地执行,越来越接近限制条件。
递归思想
分解问题,由大划小。
示例1:输入一个整数,依次打印该整数的每一位数。
想法是,将该整数通过整数划分开,例如输入1234,把1234划成123,打印4,再把123划成12,打印3,把12划成1和2,打印2,再打印1。
实现:
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
示例2:在不创建临时变量的条件下,求一字符串数组长度。
首先,字符串数组传递给函数的参数是一个数组首个元素的指针地址,
我们可以控制指针右移,直至该指针指向的元素为字符串数组的终止符号'\0',就代表到了该数组的最右侧。
实现:
int strlen(char* sz)
{
if (*sz != '\0')
{
return 1 + strlen(sz + 1);
}
else return 0;
}
示例3:将一字符串数组逆序。
要实现对其逆序,我们可以从数组两边开始,对数组的首尾的元素进行互换。然后再把剩下的字符串数组进行首尾互换,直至剩余数组长度小于2时停止。
实现:
void reverse_string(char* string)//将指针传递至函数参数,最开始传递的是数组首个元素的指针。
{
int n = strlen(string);//根据示例2,求当前数组的长度
char frist = *string; //将当前数组首个元素赋值给frist
*string = *(string + n - 1); //将当前数组末尾元素放置于首位。
*(string + n - 1) = '\0'; //临时缩小数组长度
if(strlen(string)>2) //当数组长度大于2时 进行递归。
{
reverse_string(string + 1);
}
*(string + n - 1) = frist;将首个元素放置于当前数组末尾。
}
示例4:
当我们使用递归的方法计算斐波那契数列时,会发现当数列个数较大时,计算会很慢甚至崩溃,这是因为在用递归的方法计算斐波那契数列时,有许多重复的计算,浪费了时间。
比较:
//斐波那契数列-递归
int function1(int n)
{
if (n <= 2) return 1;
else return function1(n - 1) + function1(n - 2);
}
//斐波那契数列-不递归
int function2(int n)
{
int f1 = 1;int f2 = 1;int f3 = 0;
if (n <= 2) return 1;
else
{
for (int i = 2;i < n;i++)
{
f3 = f1 + f2;
f1 = f2;
f2 = f3;
}
return f3;
}
}
可以看到,当使用递归时,代码更加简洁,但对应的,会增加重复的计算。