C++: 调试基础与常见错误

最后更新:2026-08-26

写代码不可能一次就写对,出错是常态。

真正的高手不是"不犯错",而是"能快速找到并修复错误"。

这一课,我们来学习如何调试 C++ 程序。


1. 三种错误类型

C++ 程序有三种错误,它们的发现时机修复难度都不同。

错误类型 发现时机 修复难度 示例
编译错误 编译时 ⭐(最容易) 少了分号、括号不匹配
运行时错误 运行时 ⭐⭐(中等) 除以0、数组越界
逻辑错误 运行后(结果不对) ⭐⭐⭐(最难) 算法写错、条件写反


2. 编译错误(Compiler Error)

(1) 2.1 特点

(2) 2.2 常见编译错误

错误一:少了分号

▶ 示例 2:基础编程实践(难度⭐)

CPP
#include <iostream>

int main() {
 int x = 5 // ❌ 少了分号
 std::cout << x << std::endl;
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
(程序输出)

编译错误信息:

TEXT 📖 仅展示
error: expected ';' before 'std'

💡 技巧: 编译器说"在 std 前少了分号",但真正少分号的是上一行(第4行)。


错误二:括号不匹配

CPP
#include <iostream>

int main() {
 if (5 > 3 { // ❌ 少了右括号
 std::cout << "5 > 3" << std::endl;
 }
 return 0;
}

编译错误信息:

TEXT 📖 仅展示
error: expected ')' before '{' token

💡 技巧: 用 VS Code 的括号匹配功能(光标放在括号上,对应的括号会高亮)。


错误三:变量未声明

CPP
#include <iostream>

int main() {
 x = 5; // ❌ x 没有声明
 std::cout << x << std::endl;
 return 0;
}

编译错误信息:

TEXT 📖 仅展示
error: 'x' was not declared in this scope

错误四:类型不匹配

CPP
#include <iostream>

int main() {
 int x = 3.14; // ⚠️ 警告:把 double 赋给 int,会丢失小数部分
 std::cout << x << std::endl;
 return 0;
}

编译警告信息:

TEXT 📖 仅展示
warning: narrowing conversion of '3.1400000000000001e+0' from 'double' to 'int'

💡 建议: 把警告当成错误处理!用 g++ -Wall -Wextra -Werror 编译,让警告变成错误。



3. 运行时错误(Runtime Error)

(1) 3.1 特点

(2) 3.2 常见运行时错误

错误一:除以 0

CPP
#include <iostream>

int main() {
 int x = 5;
 int y = 0;
 std::cout << x / y << std::endl; // ❌ 除以 0,运行时崩溃
 return 0;
}

运行结果:

CPP
Floating point exception (core dumped) // Linux

CPP
进程已结束,退出代码 -1073741676 // Windows

💡 修复: 在除法前检查除数是否为 0。


错误二:数组越界

CPP
#include <iostream>

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 std::cout << arr[10] << std::endl; // ❌ 访问了不存在的元素
 return 0;
}

运行结果:

CPP
0 // 输出垃圾值,或者程序崩溃

💡 提示: C++ 不会自动检查数组越界!这是 C++ 速度快的原因之一,但也是常见的 bug 来源。


错误三:未初始化变量

CPP
#include <iostream>

int main() {
 int x; // ❌ 没有初始化
 std::cout << x << std::endl; // 输出垃圾值
 return 0;
}

运行结果:

CPP
32767 // 输出垃圾值(每次运行可能不同)

💡 修复: 声明变量时就初始化。



4. 逻辑错误(Logic Error)

(1) 4.1 特点

(2) 4.2 常见逻辑错误

错误一:条件写反

CPP
#include <iostream>

int main() {
 int age;
 std::cout << "请输入年龄:";
 std::cin >> age;
 
 if (age < 18) { // ❌ 写反了!应该是 age >= 18
 std::cout << "你已经成年了" << std::endl;
 } else {
 std::cout << "你还未成年" << std::endl;
 }
 
 return 0;
}

💡 调试技巧:cout 输出关键变量的值,看看程序走到了哪里。


错误二:循环条件写错

CPP
#include <iostream>

int main() {
 // ❌ 想输出 1-10,但条件写成了 i < 10,只会输出 1-9
 for (int i = 1; i < 10; i++) {
 std::cout << i << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

错误三:= 和 == 写反

CPP
#include <iostream>

int main() {
 int x = 5;
 
 if (x = 10) { // ❌ 这是赋值,不是比较!x 变成 10,条件永远为真
 std::cout << "x 是 10" << std::endl;
 }
 
 return 0;
}

💡 防坑技巧: 把常量写在左边:if (10 = x) 会编译报错。



5. 调试方法

(1) 5.1 用 cout 调试(最简单)

在关键位置加 cout,输出变量的值,看看程序是否按预期执行。

CPP
#include <iostream>

int main() {
 int x = 5;
 int y = 10;
 
 std::cout << "[DEBUG] x = " << x << std::endl; // 调试输出
 std::cout << "[DEBUG] y = " << y << std::endl;
 
 int sum = x + y;
 
 std::cout << "[DEBUG] sum = " << sum << std::endl;
 std::cout << "结果:" << sum << std::endl;
 
 return 0;
}

💡 技巧: 调试完成后,记得删掉(或注释掉)调试输出。


(2) 5.2 用 IDE 调试器(最强大)

VS Code + C/C++ 扩展自带调试器,可以:

  1. 设置断点(让程序暂停在某一行)
  2. 单步执行(一行一行地运行)
  3. 查看变量(实时看变量的值)

使用步骤:

  1. 在 VS Code 里,点击行号左边的空白处,设置断点(会出现一个红点)
  2. F5(或点击"运行和调试"),选择"C++ (GDB/LLDB)"
  3. 程序会运行到断点处暂停
  4. F10 单步跳过,或 F11 单步进入
  5. 在左侧"变量"窗口,可以看到所有变量的值

💡 提示: 调试器是终极武器,但初学者可能觉得复杂。建议先学会用 cout 调试,再学调试器。



6. 常见错误汇总

(1) 6.1 编译错误速查表

错误信息 原因 修复
expected ';' before ... 少了分号 在上一行末尾加分号
expected ')' before ... 少了右括号 补全括号
was not declared in this scope 变量未声明 先声明变量
undefined reference to ... 函数未定义 检查函数名是否拼写错误

(2) 6.2 运行时错误速查表

错误表现 原因 修复
程序突然退出 除以 0 在除法前检查除数
输出乱码/垃圾值 数组越界 检查数组下标范围
输出奇怪的大数 变量未初始化 声明时就初始化

(3) 6.3 逻辑错误速查表

错误表现 原因 修复
结果不对 条件写反 仔细检查 if 条件
循环次数不对 循环条件写错 用笔在纸上模拟循环执行过程
永远执行不了 == 写成了 = 把常量写在左边


7. 实战:调试一个有 bug 的程序

▶ 示例 1:找出程序中的错误(难度⭐⭐)

有 bug 的程序:

CPP
#include <iostream>

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 
 // 想计算数组所有元素的和
 int sum = 0;
 for (int i = 0; i <= 5; i++) { // ❌ Bug 1:i <= 5 会导致越界
 sum += arr[i];
 }
 
 std::cout << "数组元素的和:" << sum << std::endl;
 
 int x = 5;
 if (x = 10) { // ❌ Bug 2:= 应该是 ==
 std::cout << "x 是 10" << std::endl;
 }
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
数组元素的和:15
x 不是 10

调试过程:

  1. 第一次运行: 程序崩溃(数组越界)
  1. 第二次运行: 程序输出"x 是 10"(即使 x 是 5)

修复后的程序:

CPP
#include <iostream>

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 
 int sum = 0;
 for (int i = 0; i < 5; i++) { // ✅ 修复:i < 5
 sum += arr[i];
 }
 
 std::cout << "数组元素的和:" << sum << std::endl;
 
 int x = 5;
 if (x == 10) { // ✅ 修复:== 
 std::cout << "x 是 10" << std::endl;
 } else {
 std::cout << "x 不是 10" << std::endl;
 }
 
 return 0;
}

▶ 示例 3:调试打印技巧(难度⭐)

CPP
#include <iostream>

int main() {
    int sum = 0;
    
    for (int i = 1; i <= 5; i++) {
        sum += i;
        // 调试打印:显示每次循环的值
        std::cout << "[DEBUG] i=" << i << ", sum=" << sum << std::endl;
    }
    
    std::cout << "最终结果:" << sum << std::endl;
    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
[DEBUG] i=1, sum=1
[DEBUG] i=2, sum=3
[DEBUG] i=3, sum=6
[DEBUG] i=4, sum=10
[DEBUG] i=5, sum=15
最终结果:15

预期输出:

TEXT 📖 仅展示
[DEBUG] i=1, sum=1
[DEBUG] i=2, sum=3
[DEBUG] i=3, sum=6
[DEBUG] i=4, sum=10
[DEBUG] i=5, sum=15
最终结果:15

❓ 常见问题

Q 为什么我的程序编译通过了,但运行没反应?
A 两种情况:①Windows 双击 .exe 一闪而过是正常的,应在终端运行;②程序进入了死循环,按 Ctrl+C 强制终止后检查循环条件。
Q VS Code 的调试器怎么配置?
A 按 F5 → 选择"C++ (GDB/LLDB)" → VS Code 自动生成 launch.json。重点检查:是否安装了 gdb、launch.json 的 program 路径是否正确。
Q 为什么用 cout 调试时,输出顺序不对?
A 这是缓冲区的缓存问题。用 std::endlstd::flush 强制刷新缓冲区即可。

📖 小节


📝 作业

  1. 基础题 (Difficulty ⭐): 把下面的程序改对(有 5 个 bug):
CPP
#include <iostream>

int main() {
int x = 5
int y = 10;

if (x = y) {
std::cout << "x 和 y 相等" << std::endl;
}

for (int i = 0; i <= 10; i++) {
std::cout << i << " ";
}

return 0;
}
  1. 进阶题 (Difficulty ⭐⭐): 编写一个程序,让用户输入 10 个整数,找出最大值和最小值。

  2. cout 调试,输出每次循环时变量的值

  3. 故意写一个 bug(比如初始化最大值时用了错误的值),然后用调试找出问题

  4. 挑战题 (Difficulty ⭐⭐⭐): 学习使用 VS Code 的调试器:

  5. practice-branch-loop.md 的猜数字游戏代码里设置断点

  6. F5 启动调试

  7. 用"单步执行"一步步运行,观察变量 secretNumberguessattempts 的值

  8. 截图发给我看!


8. 🚀 下一步

恭喜你!Phase 1(入门)的所有课程都学完了。 你现在已经掌握了 C++ 的基础知识——变量、数据类型、运算符、条件判断、循环、调试。

接下来我们进入 Phase 2(函数),学习如何把代码封装成可复用的模块,让程序更简洁、更易维护!

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏