目录
1.函数的嵌套调用和链式访问
1)函数嵌套调用
2)函数的链式访问 - 函数的返回值作为另一个函数的参数
2. 函数的声明和定义
1)变量的声明和定义
2)函数的声明和定义
//函数必须先声明后使用//函数的声明写在头文件里
3. 函数递归 - 程序自己调用自己,递推回归
递归的两个必要条件
例子1:函数调用不当 - 死循环
例2:接收一个整型值(无符号),按照顺序打印每一位输入1234 打印1 2 3 4
例3:编写函数,不允许创建临时变量,求字符串的长度
4.递归与迭代 - 练习
例1:求n的阶乘。(不考虑溢出)
例2:求第n个斐波那契数
方法1:第n个数等于前两个数的和
方法二:优化
迭代,从前往后算(从第3个开始往后求,n前面的两个数,再求第n) 前两个数的和等于第三个数
1.函数的嵌套调用和链式访问
函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的
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; }
2)函数的链式访问 - 函数的返回值作为另一个函数的参数
int main() { int len = strlen("abcdef"); printf("%d\n", len); //链式访问 printf("%d\n", strlen("abcdef")); //经典链式访问 printf("%d", printf("%d", printf("%d", 43)));//打印4321 //printf()返回的值是:打印字符的个数。打印43后,返回2;打印2,返回1; return 0; }
2. 函数的声明和定义
test.h 的内容放置函数的声明test.c 的内容放置函数的实现//在写大量代码的时候,例如三字棋和扫雷,可以试着这样规划代码。
1)变量的声明和定义
//变量 声明 和 定义
//先定义(声明)后使用
int b;//声明
int main()
{
//定义变量
int a = 10;
printf("%d %d\n", a,b);
return 0;
}
int b = 20;//定义
2)函数的声明和定义
//函数必须先声明后使用
//函数的声明写在头文件里
//正常在工程里,会有很多函数被调用
//通常函数定义代码写在.c文件里,函数的声明写在.h的头文件里
//在使用函数时,引用该函数的头文件,这样就能调用了//如果卖代码,不想泄露源代码,可以把写好的代码,转为静态库,然后将代码的静态库和头文件打包
//给甲方,这样甲方用#pragma comment(lib,"头文件名")就可以引用,再调用使用了
//这种只声明,再main函数后面定义的方式,是可以的,但是这样不太清晰,尽量声明定义一起写
int Add(int a, int b);//函数的声明(声明里面必须有类型,可以不写x,y) int main() { int a = 10; int b = 10; int c = Add(a, b); printf("%d\n", c); return 0; } int Add(int a,int b)//函数的定义 { return a + b; }
3. 函数递归 - 程序自己调用自己,递推回归
递归思想:把大事化小(把大型的复杂的问题,转化为一个与原问题相似的规模较小的问题来求解)
递归的两个必要条件
例子1:函数调用不当 - 死循环
int main() { printf("hehe\n"); //函数递归,main函数自己调用自己 main();//死循环打印hehe,然后栈溢出,报错 return 0; }
例2:接收一个整型值(无符号),按照顺序打印每一位
输入1234 打印1 2 3 4
//接收一个整型值(无符号),按照顺序打印每一位 //输入1234 打印1 2 3 4 //print(1234) //print(123) 4 //print(12) 3 4 //print(1) 2 3 4 //1 2 3 4 void Print(unsigned int n) { if (n > 9) { Print(n / 10); } printf("%d ",n % 10); } int main() { unsigned int num = 0; scanf("%u", &num); Print(num); return 0; }
例3:编写函数,不允许创建临时变量,求字符串的长度
//编写函数,不允许创建临时变量,求字符串的长度
//数组名是数组首元素的地址
//普通方法:创建临时变量
//int my_strlen(char* str)
//{
// int count = 0;
// while (*str != '\0')
// {
// count++;
// str++;
// }
// return count;
//}
int my_strlen(char* str)
{
if (*str != '\0')
{
return 1+my_strlen(str+1);
}
else
{
return 0;
}
}
int main()
{
char arr[10] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
4.递归与迭代 - 练习
例1:求n的阶乘。(不考虑溢出)
//普通方法:循环 //int fac(int n) //{ // int i = 0; // int ret = 1; // for (i = 1; i <= n; i++) // { // ret = ret * i; // } // return ret; //} //递归 //n <=1, fac(n)=1 //n > 1, fac(n) = n*fac(n-1) //fac(5) //fac(4)*5 //fac(3)*4 *5 //fac(2)*3 *4 *5 //fac(1)*2 *3 *4 *5 //1 *2 *3 *4 *5 //递归 int fac(int n) { if (n <= 1) { return 1; } else { return n * fac(n - 1); } } int main() { int n = 0; scanf("%d", &n); int ret = fac(n); printf("%d\n", ret); return 0; }
例2:求第n个斐波那契数
//斐波那契数列:1 1 2 3 5 8 12 21 34 55...
//n<=2,Fib(n)=1
//n>2,Fib(n)=Fib(n-1)+Fib(n-2)
方法1:第n个数等于前两个数的和
//方法1:第n个数等于前两个数的和
int count = 0;
int Fib(int n)
{
//计算第3个斐波拉契数被调用的次数
if (3 == n)//通过次数39088169次,可以发现数字越小的斐波那契数,被调用的次数越多
{
count++;
}
if (n <= 2)
{
return 1;
}
else
{
return Fib(n - 1) + Fib(n - 2);
}
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
printf("count=%d\n", count);
return 0;
}
方法二:优化
迭代,从前往后算(从第3个开始往后求,n前面的两个数,再求第n)
前两个数的和等于第三个数
//优化:迭代,从前往后算(从第3个开始往后求,n前面的两个数,再求第n) // 前两个数的和等于第三个数 int Fib(int n) { int a = 1; int b = 1; int c = 1;//因为当n=1或2的时候,返回c,这时斐波那契数为1,所以令c=1 while (n >= 3) { c = a + b; a = b; b = c; n--;//逼近循环结束条件 } return c; } int main() { int n = 0; scanf("%d", &n); int ret = Fib(n); printf("%d\n", ret); printf("count=%d\n", count); return 0; }