printfデバッグ

この節の要点

  • 変数のデータを処理ごとに標準出力(ターミナル)に表示しながらプログラムの状態を確認するデバッグ方法をprintfデバッグ と呼ぶ。

プログラムを実行中にエラーが起こった時、エラーが起こった箇所を特定するためにプログラム中の変数の中身や処理の流れを表示したいことがあります。このようなとき、ターミナルに処理毎に気になる変数の中身を表示させることをしたことがあるかもしれません。適宜System.out.println(Cではprintf)を使って確認したい変数を表示させる処理を追加し、実行してその表示された状態を確認しながら、期待通りの動作結果となるようにコード修正する、これを繰り返すデバッグ方法を printfデバッグ と呼びます[3]\(\dagger\)。

たとえば、図4のような繰り返しを使って配列の隣り合う中身を先頭から順に交換していく手続きを記述する際に、正しく操作されているか確認するためにprintfデバッグをすることができます。

int[] arr = new int[]{3, 1, 4, 1, 5, 9, 2};

for (int i = 0; i < arr.length; i = i + 1) {
	
	int x = arr[i];
	arr[i] = arr[i + 1];
	arr[i + 1] = x;
}
図4:ArrayIndexOutOfRangeExceptionが発生する場合

ArrayIndexOutOfRangeException発生時の出力タブ

図5:ArrayIndexOutOfRangeException発生時の出力タブ

図4で示すプログラムは、配列内の隣り合う要素を先頭インデックスから順に入れ替えていくプログラムを意図しています。ですが、図4を実行すると、ArrayIndexOutOfRangeExceptionが発生します(図5)。このArrayIndexOutOfRangeExceptionがなぜ発生したのか、コード修正を行うためにprintfデバッグを行ってみましょう。

第1週の課題6にて、作成したArrayPrinterクラスのprintIntメソッドが役に立ちそうです。パッケージ機能を使って呼び出してみましょう。

プロジェクトペインで、現在のプロジェクトツリー内にあるライブラリフォルダを右クリックし、右クリックメニューからプロジェクトの追加...を選びます(図6)。プロジェクトの追加ダイアログにて、chapter1debugを選択し、プロジェクトJARファイルの追加を選択してください(図7)。これにより、既に作成してある別プロジェクトのプログラムを読み込み、パッケージ名を指定することで呼び出すことができます。

ライブラリフォルダへのプロジェクトの追加

図6:ライブラリフォルダへのプロジェクトの追加

プロジェクトダイアログからプロジェクトの指定

図7:プロジェクトダイアログからプロジェクトの指定

図8で示すように、ループ中に、標準出力する命令を追加しプログラムを実行することで、強制終了する時の状態を確認しながらプログラムを作成できます。

int[] arr = new int[]{3, 1, 4, 1, 5, 9, 2};

for (int i = 0; i < arr.length; i = i + 1) {

	System.out.println("ループ回数:"+i); // ループ回数を表示してみる
	ArrayPrinter.printInt(arr); // 配列の中身がどのように変化しているか表示してみる

	int x = arr[i];
	arr[i] = arr[i + 1];
	arr[i + 1] = x;
}
図8:図4のプログラムをprintfデバッグしてみた例

図8の実行結果を図9に示します。この結果をみると、ループ回数が6のとき、すなわちi=6のときエラーが起こっていることがわかります。また実行結果の図から35行目(図10)でエラーが起きていることもわかります。

図4のプログラムをprintfデバッグ中の実行結果例

図9:図4のプログラムをprintfデバッグ中の実行結果例

図10のプログラムの内容と標準出力に表示させた変数の値i=6から、標準出力にデータを表示させないときよりも容易にエラーを特定することができるはずです。

arr[i] = arr[i + 1];
図10:図4のプログラムでエラーが起こっている行

[3]: printf() debugging - Everything2.com (20/06/04 閲覧)


\(\dagger\): Caveman Debuggingなどその他の呼称も存在しますから、この呼称がデファクト・スタンダードというわけではないです。しかし、Cを経験したことがあるプログラマであれば、どのようなことを指し示すのか理解できます。