6.函数的嵌套调用和链式访问
函数和函数之间可以有机结合的
嵌套调用
C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能再定义另一个函数,即不能嵌套定义,但可以嵌套调用函数。即在调用一个函数的过程中,又调用另一个函数
#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;
}
运行结果:
hehe
hehe
hehe
-- -- -- -- -- -- -- -- -- --
链式访问
把一个函数的返回值作为另一个函数的参数
#include <stdio.h>
#include <string.h>
int main()
{
int len = 0;
printf("%d\n", strlen("abc"));//strlen函数的返回值是字符串的长度
return 0;
}
运行结果:3
再来一个例子:
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
运行结果:4321
printf()函数的返回值是打印在屏幕上字符的个数
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
7.函数的声明和定义
函数声明
告诉编译器有一个函数叫什么、参数是什么、返回类型是什么。但是具体这个函数有没有存在,无关紧要
函数的声明一般出现在函数的使用之前,要满足先声明后使用
函数的声明一般要放在头文件中
-- -- -- -- -- -- -- -- -- --
函数定义
函数的定义是指函数的具体体现、交代函数的功能实现
#include <stdio.h>
int Add(int x, int y);//函数声明
int main()
{
int a = 0;
int b = 0;
int sum = 0;
sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
int Add(int x, int y)//函数定义
{
return x + y;
}
实际上不会这样去使用。应该自己创建一个头文件,把函数声明放在头文件(add.h)中,把函数定义放在另一个源文件中。若需要使用函数,再main函数所在源文件引用头文件即可,如:#include "add.h"(要使用双引号进行引用)①
若把函数定义在主函数之前则不声明函数也行
-- -- -- -- -- -- -- -- -- --
在自己创建头文件中:
#ifndef __ADD_H__//如果没有定义add.h
//ifndef————if not define————为了防止多次的被引用
//防止add.h被重复引用
#define __ADD_H__//那就引入add.h
//...函数声明
#endif // !__ADD_H__
//否则不需要引入
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
8.函数递归
什么是递归
程序调用自身的编程技巧称为递归。递归作为一种算法在程序设计语言中广泛引用。一个过程或者函数在其定义或者说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可以描述出解题思路过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思想方式在于:把大事化小
-- -- -- -- -- -- -- -- -- --
递归的两个必要条件
存在限制条件时,当满足这个限制条件,递归便不在继续
每次递归调用之后越来越接近这个限制条件
-- -- -- -- -- -- -- -- -- --
示例
#include <stdio.h>
int main()
{
printf("hehe\n");
main();//在主函数中调用主函数
return 0;
}
运行结果:
hehe
hehe
...
(无限打印hehe)
一段时间后报错并弹出stack overflow(栈溢出)
没调用一次函数就会在栈区开辟并占用一块空间,栈区空间被耗干时就会弹出stack overflow
内存②
-- -- -- -- -- -- -- -- -- --
练习
接收一个整型值(无符号),按照顺序打印它的每一位。例如输入6941,输出6 9 1 4
#include <stdio.h>
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int num = 6914;
print(num);
return 0;
}
运行结果:6 9 1 4③
-- -- -- -- -- --
编写一个函数不允许创建临时变量,求字符串长度(模拟实现strlen)
创建临时变量
#include <stdio.h>
int my_strlen(char* str ) //int my_strlen(char str[])一样的
{
int count = 0;//创建临时变量
while (*str != '\0')
{
count++;
str++;//指针+1.让“b”和地址编程“t”的地址
}
return count;
}
int main()
{
char arr[] = "bit";
int len = my_strlen(arr);
printf("len=%d\n",len);
return 0;
}
运行结果:len=3
不创建临时变量
#include <stdio.h>
//用递归的方法,大事化小
//思路:
//my_strlen("bit");
//1+my_strlen("it");
//1+1+my_strlen("t");
//1+1+1+my_strlen("");
//1+1+1+0
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);
printf("len=%d\n", len);
return 0;
}
运行结果:len=3
第十三行的return 1 + my_strlen(str + 1);是为了获得下一个地址
在从b → i → t → '\0'的过程中,if的条件判断为假,走else
即开始return 0;(返回上一个函数的位置)
my_strlen b:返回1+1+1+0
⬇ ⬆
my_strlen i: 返回1+1+0
⬇ ⬆
my_strlen t: 返回1+0
⬇ ⬆
my_strlen '\0': 返回0
-- -- -- -- -- -- -- -- -- --
递归与迭代
练习:求n的阶乘(不考虑溢出)
递归
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Fac1(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * Fac(n - 1);
}
}
int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
ret = Fac(n);
printf("%d\n", ret);
return 0;
}
运行结果:
输入:6
输出:720
-- -- -- -- -- --
迭代(循环)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Fac2(int n)
{
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret *= i;
}
return ret;
}
int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
ret = Fac2(n);
printf("%d\n", ret);
return 0;
}
-- -- -- -- -- -- -- -- -- --
练习:计算第n个斐波那契数
递归
#define _CRT_SECURE_NO_WARNINGS
#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("%d\n", ret);
return 0;
}
运行结果:
输入5,打印5
输入10,打印55
输入50,很长时间都不会弹出结果,计算机在不停的计算(不考虑溢出)
50
49 48
48 47 47 46
47 46 46 45 46 45 45 44
...可见计算了非常多相同的数且计算量大到恐怖
因此不适合使用递归
使用循环来解决(迭代)
-- -- -- -- -- --
迭代
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;//前两个数都是1
int c = 1;//如果输入的n小于2,便于直接返回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("%d\n", ret);
return 0;
}
运行结果:
输入5,打印5
输入10,打印55
输入50,打印-298632863(瞬间弹出结果,不管对不对但是非常快;早就溢出了)
附
①
②
③