11.C 语言学习:递归、宏定义、预处理、汉诺塔、Fibonacci 等

C 语言学习:递归、宏定义、预处理、汉诺塔、Fibonacci 等

1. 函数递归

什么是递归?

函数调用自己本身的行为称为递归。

递归本质上也是一种循环,但实现方式不同,特点是:

✔ 优点

  • 逻辑清晰、代码简短
  • 适合解决回溯、树形结构、数学归纳类问题(如汉诺塔、斐波那契)

❗ 必须满足两个条件

  1. 必须要有结束条件,否则会导致无限递归 → 栈溢出 Segmentation fault
  2. 避免递归层次过深

2. 字符串打印与 strlen()

通过递归前先学习字符串处理:

c 复制代码
void show_str(char a[])
{
    int len = strlen(a); // 字符串真实长度(不含'\0')
    for(int i=0; i<len; i++)
    {
        putchar(a[i]);
    }
    printf("\nstrlen %lu\n", strlen(a));
}

注意事项:

  • sizeof(str) 得到的是数组容量,例如 char str[100] → 100 字节
  • strlen(str) 得到的是字符串长度,例如 "hello" → 5

这是 C 语言中 字符串与字符数组的关键区别。


3. 闰年判断函数

闰年规则:

  • 能被 4 整除但不能被 100 整除
  • 或能被 400 整除
c 复制代码
int isLeapYear(int year)
{
    return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}

用于遍历打印 1900 ~ 2024 之间的所有闰年:

c 复制代码
for(int i=1900; i<2025; i++)
{
    if(isLeapYear(i))
        printf("year is %d\n", i);
}

4. 递归的典型应用

4.1 阶乘计算

c 复制代码
int fun(int n)
{
    if(n == 1) return 1;
    return n * fun(n - 1);
}

递归非常适合数学归纳结构的函数表达式。


4.2 汉诺塔问题

问题描述 :

三根柱子 A、B、C,将 n 个盘从 A 移动到 C,每次只能移动一个盘,大盘不能压在小盘上。

c 复制代码
void haonuota(int n, char src, char tmp, char dst)
{
    if (n == 1)
    {
        printf("%c -> %c\n", src, dst);
    }
    else
    {
        haonuota(n - 1, src, dst, tmp);
        printf("%c -> %c\n", src, dst);
        haonuota(n - 1, tmp, src, dst);
    }
}

汉诺塔体现了递归的 "逆向思维":

  1. 先把 n-1 个盘移动到中间柱子
  2. 把最大盘移动到目标柱子
  3. 再把 n-1 个盘移到目标柱子

4.3 Fibonacci 数列

递归版:

c 复制代码
int fib(int n)
{
    if(n == 1 || n == 2)
        return 1;
    return fib(n-1) + fib(n-2);
}

但这种写法效率非常低(指数复杂度)。

推荐:循环版 Fibonacci(性能好)

c 复制代码
int fib_loop(int n)
{
    if (n == 1 || n == 2)
        return 1;

    int a = 1, b = 1, c = 0;

    for(int i = 3; i <= n; i++)
    {
        c = a + b;
        a = b;
        b = c;
    }
    return c;
}

5. 宏定义(

宏属于预处理阶段,特点是:

  • 代码替换,不会执行运算
  • 无类型检查
  • 效率高,没有函数调用开销

示例:

c 复制代码
#define PI 3.14
#define GETMAX(x,y) ((x)>(y)?(x):(y))
#define M 50
#define N (M+M)

带参宏建议:

所有参数加括号避免优先级错误,例如:

c 复制代码
#define GETMAX(x,y) ((x)>(y)?(x):(y))

5.1 多行宏

c 复制代码
#define PRINT(a,b,c) do{ \
    printf("%d\n", a);   \
    printf("%d\n", b);   \
    printf("%d\n", c);   \
}while(0)

6. C 语言预处理

编译步骤:

  1. 预处理 (处理 #include, #define,宏展开)
  2. 编译(变成汇编)
  3. 汇编(生成 .o 目标文件)
  4. 链接(生成最终 a.out 或可执行程序)

7. 头文件

#include <...>:从系统目录中查找,比如 /usr/include
#include "...":先从当前目录查找,再去系统目录查找

头文件一般包含:

  • 宏定义
  • typedef
  • 函数声明
  • extern 声明

防止头文件被重复包含

c 复制代码
#ifndef _FUNC_H_
#define _FUNC_H_

extern int add(int a, int b);

#endif

8. 条件编译

常见语法:

c 复制代码
#if
#elif
#else
#endif

判断宏是否存在:

c 复制代码
#ifdef DEBUG
#endif

#ifndef DEBUG
#endif

非常适合调试或不同平台切换。

相关推荐
邪修king3 小时前
Re:Linux 系统篇(三十五):进程间通信Chapter2:从匿名管道到进程池:Linux 进程间通信实战(深度理解「先描述,再组织」)
java·linux·运维
2301_777998343 小时前
ARP协议进阶:ARP缓存、RARP与ARP欺骗原理解析
linux·服务器·网络·网络协议·缓存
阿里嘎多学长9 小时前
2026-10-20 GitHub 热点项目精选
开发语言·程序员·github·代码托管
dadaobusi9 小时前
学习: PCIe 6.0 的 L0p
学习
布吉岛的石头9 小时前
Java 程序员第 50 阶段2:预训练的目标函数:自回归语言建模本质
java·开发语言·人工智能·深度学习·回归·transformer
小羊没烦恼!10 小时前
铁道部新客票系统设计(二)
开发语言·前端·数据库·python·oracle·c#·php
quantdash_cc10 小时前
从实时行情到价格观察表:用 Python 和 Pandas 构建策略输入数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
Zenova EdgeOS10 小时前
Linux 内核日志 dmesg 进阶实战:从现场过滤到持久化闭环
linux·运维·服务器
郝亚军11 小时前
ec_private.pem的生成方法
linux·运维·服务器
燕落南枝11 小时前
CSS 学习:类型选择器与 AI 注释实战
css·人工智能·学习