C Language Study: Recursion, Macros, Preprocessing, Hanoi Tower, Fibonacci, and More
1. Function Recursion
What is Recursion?
Recursion refers to a function calling itself.
Essentially, recursion is another form of looping, but achieved through function calls instead of iteration.
✔ Advantages
- Clear and concise logic
- Ideal for solving backtracking, tree-structured, and mathematically inductive problems
(e.g., Hanoi Tower, Fibonacci)
❗ Two rules must be satisfied
-
There must be a termination condition
Otherwise it will recurse infinitely → stack overflow (Segmentation fault) -
Avoid overly deep recursion levels
Recursion consumes stack memory.
2. String Printing and strlen()
Before diving into recursion, let’s review string processing:
void show_str(char a[])
{
int len = strlen(a); // Actual length (not counting '\0')
for(int i = 0; i < len; i++)
{
putchar(a[i]);
}
printf("\nstrlen %lu\n", strlen(a));
}
Notes
sizeof(str)returns the array capacity, e.g.char str[100]→ 100 bytesstrlen(str)returns the string length, e.g."hello"→ 5
This is a crucial distinction between:
✔ character arrays
✔ C-style strings
3. Leap Year Determination Function
Leap year rules:
- Divisible by 4 but not by 100
- OR divisible by 400
int isLeapYear(int year)
{
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
Print leap years between 1900 and 2024:
for(int i = 1900; i < 2025; i++)
{
if(isLeapYear(i))
printf("year is %d\n", i);
}
4. Classic Recursion Applications
4.1 Factorial Calculation
int fun(int n)
{
if(n == 1) return 1;
return n * fun(n - 1);
}
Perfect example of a mathematically inductive recursive structure.
4.2 The Tower of Hanoi Problem
Problem description:
Given three rods A, B, C and n disks, move all disks from A to C following the rules:
- Only one disk can be moved at a time
- No disk may be placed on top of a smaller disk
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);
}
}
Recursive logic:
- Move n-1 disks from src → tmp
- Move the largest disk from src → dst
- Move n-1 disks from tmp → dst
4.3 Fibonacci Sequence
Recursive version:
int fib(int n)
{
if(n == 1 || n == 2)
return 1;
return fib(n-1) + fib(n-2);
}
⚠ Very inefficient (exponential complexity).
✔ Recommended: Loop-based Fibonacci (much faster)
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. Macro Definitions (Macros)
Macros operate during the preprocessing stage, not runtime.
Characteristics:
- Simple text substitution
- No type checking
- No function call overhead
Examples:
#define PI 3.14
#define GETMAX(x,y) ((x) > (y) ? (x) : (y))
#define M 50
#define N (M + M)
Macro best practices
Wrap all parameters in parentheses to avoid precedence issues:
#define GETMAX(x,y) ((x) > (y) ? (x) : (y))
5.1 Multi-line Macros
#define PRINT(a,b,c) do{ \
printf("%d\n", a); \
printf("%d\n", b); \
printf("%d\n", c); \
}while(0)
6. C Language Preprocessing
Compilation stages:
- Preprocessing
Handle#include,#define, macro expansion - Compilation
Convert to assembly - Assembly
Produce.oobject files - Linking
Generate final executable (a.out or custom name)
7. Header Files
#include <...> → search system directories (e.g., /usr/include)
#include "..." → search current directory first, then system directories
Header files commonly contain:
- Macro definitions (
#define) typedefalias definitions- Function declarations
externvariable declarations
Preventing multiple inclusion
#ifndef _FUNC_H_
#define _FUNC_H_
extern int add(int a, int b);
#endif
8. Conditional Compilation
Useful for platform-dependent code or debugging.
#if
#elif
#else
#endif
Check whether a macro exists:
#ifdef DEBUG
#endif
#ifndef DEBUG
#endif
!

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



