算法(欧几里得算法):
gcd(a, b) = gcd(b, a % b),直到 a % b == 0
int gcd(int a, int b) {
while (b != 0) {
int temp = a % b;
a = b;
b = temp;
}
return a;
}
// 递归版本
int gcd_rec(int a, int b) {
return b == 0 ? a : gcd_rec(b, a % b);
}
示例:gcd(48, 18) → gcd(18, 12) → gcd(12, 6) → gcd(6, 0) → 6
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand((unsigned)time(NULL)); // 设置随机种子
int target = rand() % 100 + 1; // 1~100 的随机数
int guess, attempts = 0;
printf("猜一个 1~100 之间的数字\n");
do {
printf("你的猜测:");
scanf("%d", &guess);
attempts++;
if (guess > target) {
printf("太大了!\n");
} else if (guess < target) {
printf("太小了!\n");
} else {
printf("恭喜!%d 次猜中!\n", attempts);
}
} while (guess != target);
return 0;
}
定义:
#include <stdio.h>
int main(void) {
int n;
printf("输入 n:");
scanf("%d", &n);
long long a = 1, b = 1;
printf("前 %d 项:", n);
for (int i = 1; i <= n; i++) {
printf("%lld ", a);
long long next = a + b;
a = b;
b = next;
}
printf("\n");
return 0;
}
输出(n=10):1 1 2 3 5 8 13 21 34 55
注意:
int只能存到第 46 项左右,更大需用long long
问题:公鸡 5 元/只,母鸡 3 元/只,小鸡 1 元/3 只,100 元买 100 只,各有几只?
// x: 公鸡, y: 母鸡, z: 小鸡
for (int x = 0; x <= 20; x++) { // 最多 20 只公鸡
for (int y = 0; y <= 33; y++) { // 最多 33 只母鸡
int z = 100 - x - y; // 总数 100
if (z % 3 == 0 && // 小鸡必须是 3 的倍数
5 * x + 3 * y + z / 3 == 100) { // 总价 100
printf("公鸡%d只,母鸡%d只,小鸡%d只\n", x, y, z);
}
}
}
穷举法:枚举所有可能,筛选满足条件的解
最基本也最常用的方法——在关键位置插入 printf
for (int i = 0; i < n; i++) {
printf("[DEBUG] i=%d, arr[i]=%d, sum=%d\n", i, arr[i], sum);
sum += arr[i];
}
技巧:
fprintf(stderr, ...) 输出到标准错误流,不会被重定向干扰__FILE__、__LINE__、__func__ 宏标记位置:fprintf(stderr, "%s:%d [%s] x=%d\n", __FILE__, __LINE__, __func__, x);
#include <assert.h>
double safe_sqrt(double x) {
assert(x >= 0); // 若 x < 0,程序终止并打印错误信息
return sqrt(x);
}
#include <assert.h> 之前定义 NDEBUG 可禁用所有断言:#define NDEBUG
#include <assert.h> // 所有 assert 变为空操作
编译时加 -g 生成调试信息:gcc -g -o prog prog.c
| 命令 | 作用 |
|---|---|
gdb ./prog |
启动调试 |
run / run arg1 arg2 |
运行程序 |
break main / break prog.c:20 |
设置断点 |
next(n) |
单步执行(不进入函数) |
step(s) |
单步执行(进入函数) |
print x |
查看变量值 |
continue(c) |
继续运行到下一个断点 |
backtrace(bt) |
查看调用栈 |
quit |
退出 GDB |
| 错误类型 | 示例 | 排查方法 |
|---|---|---|
| 语法错误 | 漏分号、括号不匹配 | 编译器报错,逐行检查 |
| 逻辑错误 | 条件写反、差一错误 | 打印中间值、手动模拟 |
| 越界访问 | arr[10] 但数组只有 10 个元素 |
GDB 观察、AddressSanitizer |
| 死循环 | 忘记更新循环变量 | GDB 中 Ctrl+C 查看位置 |
| 未初始化变量 | 局部变量未赋值 | 编译警告 -Wall、Valgrind |
| 整数溢出 | int 乘法结果超出范围 |
用更大类型或检查边界 |
编译选项推荐:
gcc -Wall -Wextra -std=c11 -g -fsanitize=address -o prog prog.c
-fsanitize=address:运行时检测数组越界和内存泄漏
break(除非有意穿透)while(先判断)、do-while(先执行)、for(最常用)下一章:第5章 函数