一、函数递归(Recursion)
1. 概念
递归:函数自己调用自己,属于一种特殊的循环方式。
2. 递归的两大注意点(必须掌握)
(1)必须有“结束条件”
没有结束条件 → 无限递归 → 最终导致:
Segmentation fault (core dumped)
原因:递归每进入一次都会申请一段栈空间,栈空间耗尽就崩溃(栈空间一般8M大小)。
(2)避免递归层次过深
例如:①fib(50) ②深度特别大的DFS 等等问题会导致调用栈过大。
3. 递归的应用场景
(1)回溯法(八皇后、全排列)
(2)逆向思维问题
(3)树结构遍历
(4)汉诺塔
(5)斐波那契数列
(6)深度优先搜索 DFS
4.递归示例
(1)汉诺塔问题
void HanNuoTa(int n, char src, char tmp, char dst)
{
if(n == 1)
{
printf("%c->%c\n", src, dst);
}
else
{
HanNuoTa(n-1, src, dst, tmp);
printf("%c->%c\n", src, dst);
HanNuoTa(n-1, tmp, src, dst);
}
}
(2)递归求 Fibonacci 数
int fib(int n)
{
if(n == 1 || n == 2)
{
return 1;
}
return fib(n-1) + fib(n-2);
}
二、带参宏 vs 函数
1. 带参宏的特点
| 特点 | 说明 |
|---|---|
| 无参数类型检查 | 纯文本替换 |
| 无真正的返回值 | 只是替换,不计算 |
| 没有参数传递开销 | 因为不调用函数 |
| 代码块会展开 | 体积变大 |
| 速度快 | 无函数调用开销 |
| 适合简单逻辑 | 复杂逻辑不适用 |
备注:带参宏必须注意括号!!!
#define ADD(a,b) ((a)*(b)) //带括号
#define ADD(a,b) a*b //不带括号
例如:ADD(3,4+5)
带括号 → ((3)*(4+5)) 正确
不带括号 → 3*4+5 → 错
2. 函数(真实函数)的特点
| 特点 | 说明 |
|---|---|
| 有类型检查 | 安全 |
| 有返回值类型 | 受类型限制 |
| 需要栈帧 | 有调用开销 |
| 体积小 | 不会展开 |
| 适合复杂逻辑 | 多行代码 |
3.对比总结
| 项目 | 带参宏 | 函数 |
|---|---|---|
| 类型检查 | 无 | 有 |
| 返回值 | 无 | 有 |
| 参数传递 | 直接替换 | 需要传参 |
| 执行效率 | 高 | 略低 |
| 可读性 | 差 | 好 |
| 代码大小 | 增大(展开) | 小(共用) |
| 适合 | 简单功能 | 复杂逻辑 |
三、预处理指令(Preprocessing)
GCC 编译过程:
1.预处理(处理 # 相关内容)
2.编译(C → 汇编)
3.汇编(汇编 → .obj目标文件)
4.链接(生成可执行文件)
备注:所有以 # 开头的都是预处理指令。
四、常用预处理指令
1. 宏定义(与带参宏)
#define PI 3.14
#define ADD(a,b) ((a)+(b))
规则:(1)不加分号 ;
(2)建议宏名用大写
(3)能带括号的尽量都带上
2. 头文件包含
#include <stdio.h> // 直接到系统目录下查找,系统目录:/usr/include
#include "my.h" // 先在当前目录查找,没找到再到系统目录查找
找不到头文件 →
fatal error: file.h: No such file or directory
3. 条件编译(重点)
(1)基本形式
#if 表达式
代码1
#endif
(2)带 else
#if 表达式
代码1
#else
代码2
#endif
(3)带 elif
#if 表达式1
代码1
#elif 表达式2
代码2
#else
代码3
#endif
4. 判断宏是否定义
(1)已经定义?
#ifdef DEBUG
printf("debug on\n");
#endif
(2)没有定义?
#ifndef DEBUG
#define DEBUG
#endif
五、头文件的内容
.h 文件中一般存放:
1. 宏定义
#define MAX 100
2.typedef 别名
typedef unsigned int size_t;
3.函数声明
int add(int a, int b);
4.全局变量的 extern 声明
extern int result;
六、避免头文件被重复包含(防止重复定义)
标准写法:
#ifndef _FUNC_H_
#define _FUNC_H_
extern int result;
extern int add(int a, int b);
extern int sub(int a, int b);
#endif // _FUNC_H_
作用:让头文件只被编译一次,避免 redefinition 错误。
1251

被折叠的 条评论
为什么被折叠?



