C++: デバッグの基礎
最終更新:2026-08-31
すべてのプログラマー——プロでも——バグだらけのコードを書く。初心者と熟練者の違いは、間違いをするかどうかではなく、どれだけ早く見つけて修正できるか。このレッスンでは、毎日使うデバッグスキルを教える。
1. 3種類のエラー
(1) 1.1 コンパイル時エラー
これらはプログラムが実行される前にコンパイラに捕捉される。
TEXT
📖 参照専用
int x = 5
cout << x << endl; // ❌ セミコロンがない!
何が表示されるか: コンパイラがファイル名と行番号付きのエラーメッセージを出力。
修正方法: エラーメッセージを注意深く読む。通常、問題の場所と期待されることが正確に書かれている。
(2) 1.2 実行時エラー
これらはプログラム実行中に発生。クラッシュしたり異常な動作をする。
CPP
int arr[5] = {1,2,3,4,5};
cout << arr[100] << endl; // ❌ 配列インデックス範囲外
int x = 10 / 0; // ❌ ゼロ除算
何が表示されるか: クラッシュ、「セグメンテーション違反」、または間違った出力。
修正方法: コードをトレース。配列範囲、ゼロ除算、ヌルポインターをチェック。
(3) 1.3 論理エラー
プログラムはクラッシュせずに実行されるが、間違った結果を生成。これらが最も見つけにくい。
CPP
// 摂氏を華氏に変換するはず
double celsius = 100;
double fahrenheit = celsius * 9/5 + 32; // ✅ 正しい: 212
double wrong = celsius * 9/5 - 32; // ❌ 間違い: 148
何が表示されるか: プログラムは「動く」が間違った答えを出す。
修正方法: ここでデバッグテクニックが輝く。
2. coutデバッグメソッド
最も単純なデバッグテクニック:すべてを出力。
CPP
#include <iostream>
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
std::cout << "[DEBUG] i=" << i << ", result=" << result << std::endl;
}
return result;
}
int main() {
std::cout << factorial(5) << std::endl;
return 0;
}
出力:
TEXT
📖 参照専用
[DEBUG] i=1, result=1
[DEBUG] i=2, result=2
[DEBUG] i=3, result=6
[DEBUG] i=4, result=24
[DEBUG] i=5, result=120
120
💡 ヒント: デバッグ出力に
[DEBUG]プレフィックスを付けると、後で簡単に見つけて削除できる。本番コードにはデバッグ出力を残さない。
3. IDEデバッガの使用
VS Codeのデバッガでできること:
- ブレークポイントの設定 —— 行番号をクリックしてそこで実行を一時停止
- ステップオーバー —— 1行ずつ実行
- ステップイン —— 関数に入って内部で何が起きるか見る
- 変数のウォッチ —— 値がリアルタイムでどう変わるか見る
(1) VS Codeでのデバッガ設定
- C/C++ Extension Packをインストール(デバッグツール付き)
.cppファイルを開くF5を押してデバッグ開始- 「C++ (GDB/LLDB)」環境を選択
- 行番号をクリックしてブレークポイントを設定
F10を押してコードをステップ実行
4. コンパイラ警告
警告はエラーではないが、コンパイラが「これは怪しい」と言っている。警告をエラーとして扱う。
CPP
// コンパイル: g++ -Wall -Wextra -Werror program.cpp
| フラグ | 効果 |
|---|---|
-Wall |
最も一般的な警告を有効化 |
-Wextra |
追加の警告を有効化 |
-Werror |
すべての警告をエラーとして扱う |
▶ サンプル 1:バグを探す(難易度 ⭐⭐)
CPP
#include <iostream>
int main() {
int x; // バグ1: 未初期化変数
std::cout << x; // 出力は予測不能!
int arr[5];
arr[5] = 10; // バグ2: 配列範囲外
for (int i = 0; i <= 5; i++) { // バグ3: i < 5 であるべき
arr[i] = i;
}
return 0;
}
💡 ヒント:
-Wall -Wextra -Werrorでコンパイルすれば、上記の3つのバグすべてを検出!
▶ サンプル 2:coutで論理エラーをデバッグ(難易度 ⭐⭐)
CPP
#include <iostream>
int calculateSum(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
std::cout << "[DEBUG] i=" << i << ", sum=" << sum << std::endl;
}
return sum;
}
int main() {
int result = calculateSum(5);
std::cout << "最終結果: " << result << 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
▶ サンプル 3:アサーションでデバッグ(難易度 ⭐⭐)
CPP
#include <iostream>
#include <cassert>
int safeDivide(int a, int b) {
assert(b != 0 && "ゼロ除算!");
return a / b;
}
int main() {
int x = 10;
int y = 2;
std::cout << "結果: " << safeDivide(x, y) << std::endl;
// デバッグモードではアサーション失敗をトリガー
// std::cout << safeDivide(10, 0) << std::endl;
return 0;
}
出力:
TEXT 📖 参照専用結果: 5
❓ よくある質問
Q プログラムはコンパイルできるが、実行しても出力が表示されない?
A 2つの可能性:①Windowsで.exeをダブルクリックするとターミナルが開いてすぐ閉じる——CMD/PowerShellから実行する。②プログラムが無限ループ——Ctrl+Cで終了。
Q VS Codeデバッガをどう設定?
A F5 → 「C++ (GDB/LLDB)」を選択 → VS Codeがlaunch.json設定を自動生成。gdbがインストールされていること、プログラムパスが正しいことを確認。
Q なぜcoutデバッグ出力の順序がおかしい?
A これはバッファリングの問題。即座に出力するには
std::endl(フラッシュする)またはstd::flushを使う。📖 まとめ
- 3種類のエラー:コンパイル時(最も簡単)、実行時(普通)、論理(最も難しい)
-Wall -Wextra -Werrorでコンパイルして問題を早期に検出coutデバッグメソッド:重要なポイントで変数値を出力- IDEデバッガでブレークポイントを設定し、コードをステップ実行
- よくあるバグ:未初期化変数、オフバイワンエラー、セミコロン忘れ
📝 練習問題
-
初級(難易度 ⭐): 以下のバグだらけのプログラムを修正(5つのバグ):
CPP#include <iostream> int main() { int x cout << "数を入力: "; cin >> x if (x = 5) { std::cout << "5を入力しました" << std::endl; } int arr[3] = {1,2,3}; std::cout << arr[3] << std::endl; return 0 } -
中級(難易度 ⭐⭐): 各種エラー(コンパイル時、実行時、論理)を意図的に含むプログラムを書く。1つずつ修正し、何を変更したか文書化。
-
上級(難易度 ⭐⭐⭐): 再帰関数を実装し、VS Codeデバッガを使って各再帰呼び出しをステップ実行。コールスタックの変化と各レベルの変数値をメモ。デバッガのスクリーンショットを撮る。