C语言函数(三)
函数的递归调用
定义:函数在函数体内部,调用自己的操作,称为递归。
递归操作可以替换循环,但是反过来,循环不能替换递归。
应用:需要回溯问题(阶乘、斐波那契数列)
斐波那契数列
#include
int feibo(int n)
{
if(1==n||2==n)
{
return 1;
}
else
{
return feibo(n-1)+feibo(n-2);
}
}
int main()
{
int ret=feibo(10);
printf("feibo10 is:%d
",ret);
return 0;
}
- 递归函数需要设计结束条件,如果没有终止条件,栈区会被耗尽,程序就会崩溃。函数在被调用的时候,都会开辟一个内存空间,最少保留返回地址。
- 避免深层次递归
- 递归相对循环来说,开销大。
阶乘
#include
int fun(int num)
{
if(1==num)
{
return 1;
}
else
{
return num*fun(num-1);
}
}
int main()
{
int ret=fun(4);
printf("ret=%d
",ret);
return 0;
}
预处理指令
与#开头的相关指令有关
1.宏定义
2.包含头文件
3.条件与处理
gcc编译的4个步骤
- 预处理 gcc -E 1.c -o 1.i
- 编译 gcc -S 1.c -o 1.s
- 汇编 gcc -c 1.c -o 1.o
- 链接 gcc 1.c -o a.out
1.宏定义
#define PI 3.1415
#define 宏名 宏值
大部分情况,宏定义放在文件开头。
不要加分号。
宏定义是代码替换,中间不进行任何的数据计算。
宏定义的标识符一般都大写。
在gcc预处理阶段,直接替换。
2.带参宏
define ADD(a,b) a+b
define 带参宏(参数1,参数2) 字符串
带参宏和函数的区别
- 带参宏没有参数的类型检查,不涉及返回值。
- 预处理过程中,是代码的替换。函数会有参数的传递。
- 在代码替换的过程中,代码体积变大。
- 没有函数调用的开销(栈空间,需要保留函数的返回地址)
- 带参宏功能相对简单,功能复杂用函数
- 参数如果可以带括号,尽量都括起来,避免因为运算优先级导致结果出问题
#define ADD(a,b) (a+b)
#define M 50
#define N ((M)+(M))
#define MAX(a,b) ((a)>(b)?(a):(b))
3.#include
包含头文件,把被包含的文件内容,复制一份到#include的地方,只包含头文件(.h)。
#include
gcc在查找头文件的路径是 /usr/include,没找到就报错
#include"2.h" gcc在查找头文件的路径,生成a.out的路径,如果没有,会去系统头文件目录中查找,没找到就报错
头文件中的内容
- 自定义(构造类型)类型的说明
- 全局变量的声明 extern int a;在整个工程中,声明可以是多次,但是定义只能一次。
- 全局函数的声明 extern int add(int ,int );可以没有形参的名字
- 宏定义,带参宏
4.条件预处理
#if #if表达式1 如果表达式1为真,执行语句块1
语句块1
#elif #elif 表达式2 如果表达式2为真,执行语句块2
语句块2
#else #if,#elif 都没为真
语句块3
#endif
#if 0 //代码屏蔽
#endif
#ifdef 宏名 // 前面是否有定义过这个宏名,如果有定义,执行语句块4
语句块4
#endif
#ifndef 宏名// 前面是否定义过这个宏名,如果没有定义,执行语句块5
语句块5
#endif







