目录
函数嵌套
函数不可以嵌套定义。
函数和函数之前可以有机的组合。函数的函数体内可以调用其他函数。
函数链式访问
把一个函数的返回值作为另一个函数的参数。
举个例子:
这就是调用strlen函数,并把它的返回值直接作为printf函数的实参。当然自定义函数也可以这样。
函数声明
函数的定义是在创建一个函数,函数的声明是告知编译器有这么一个函数,它的参数是什么,返回类型是什么,函数名是什么,但是真实存不存在无所谓。
因为代码在执行的时候是从上往扫描,并从main函数开始执行的,如果一个自定义函数定义在了main函数之后,导致在调用该函数的时候却还没有执行定义函数,从而使编译器报错或者警告。
在调用函数的时候首先对该函数进行声明就可以避免这个问题的发生。声明方法:跟定义时相似,但是不用把函数的函数体加进来,且不用声明函数的形参,只需要声明形参的类型和返回值类型即可,声明是一条语句故要加上封号。声明时可以加上参数的标识符,也可以不加。
对于声明的位置没有要求,无论main函数内部还是外部都可,只需要在调用该函数语句之前即可。满足先声明后使用。
但其实,函数的声明一般都放头文件里面,而不是瞎放。把需要调用的函数放在.h头文件里面然后.c文件里面声明头文件即可。而函数的定义放在与之.h文件对应的.c文件里。
//在利用下标控制数组的时候千万记得数组的最后一个元素下标往往就是字符串长度-1;
函数递归
简单来说,函数自己调用自己就是函数递归。
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小。
递归的必要条件:
存在限制条件,当满足这个条件时,递归不再继续。
每次调用递归之后越来越接近这个限制条件。
否则一定会陷入死循环导致栈溢出。
内存:
里面有栈区,堆区,静态区。
栈区:局部变量和函数的形参,一般放的是一些临时的空间和变量。
堆区:是用来动态内存分配的。(malloc/free,calloc,realoc)
静态区:全局变量,静态变量。
每一次递归都都需要为这一次函数的形参重新分配新的变量空间,那么递归层次太深会导致栈溢出。
指针变量加 1 表示跳过该指针变量对应基类型所占字节数大小的空间,在 VC++ 6.0 中,整型占 4 个字节,故对于整型指针变量来说,指针值加 1 对应地址值加 4,即跳过 4 个字节;字符型占 1 个字节,故字符型指针变量加 1,对应地址值也加 1,即跳过 1 个字节。. double 型占 8 个字节,故 double 型指针变量加 1,对应地址值加 8,即跳过 8 个字节。
递归注意事项:
1:一定不能死递归,必须有跳出条件和每次递归逼近跳出条件否则必然栈溢出。
2:递归的层次不能太深,也可能导致栈溢出。
//递归字符串逆序
思路:把逆序的过程分为两部分,第一部分:把第一个字符和最后一个字符交换,第二部分:逆序第二个字符到倒数第二个字符这个字符串。
则第二部分为递归,第二部分的第一部分则为把二个字符到倒数第二个字符交换,第二部分的第二部分是逆序第三个字符和倒数第三个字符这个字符串,一直循环下去…大多数递归思路皆是如此。
- 先把字符串第一个字符存起来
- 然后把最后一个字符放在第一个字符里面
- 把最后一个字符变成\0,使得递归时传入的字符串为第二个字符到倒数第二个字符这段字符组成的字符串。
- 递归,传入的字符串在原来的基础上没有了第一个字符和最后一个字符。
- 把存起来的第一个字符放在最后的那个\0里面。
注意:递归需要有限制条件,否则将跑死 (栈溢出)。
函数这节学到递归也差不多拉倒了,细节都在课本和实践中。