第5回
制御構造と変数(1) if~条件判断と分岐の基本

予想外の入力に対処する

常に規定されたとおりの動きをするだけなら、プログラムは単純なものです。そのときの状況によって異なる処理を実行することで、プログラムは柔軟な動きをします。その基本は“if”(もし~だったら)です。

数値以外を入力したら……?!

前回(第4回)、キーボードから入力した値を10倍して表示するプログラム(リスト1)を紹介しました。このプログラムを実行すると、画面に
Input number :
と表示されて入力を受け付けます。このとき、キーボードから“3”と入力すれば
3 * 10 = 30
のように正しく(期待したとおりに)計算結果が表示されますが、例えば“A”や“%”のように《数値ではない文字》を入力するとどうなるでしょう? その結果は処理系によって異なり、Visual C++ 2005の場合は、
Input number : A
-858993460 * 10 = -8
のようになります。LSI C-86で試したら以下のようになりました。
Input number : A
307 * 10 = 3070
どちらの場合も、入力を“a”、“x”、“%”のように変更しても同じ結果となります。

リスト1:入力した値の10倍を表示するプログラム(標準的なCのソース)
#include <stdio.h>

int	main(void)
{
	int num;

	printf("Input number : ");
	scanf("%d", &num);
	printf("%d * 10 = %d\n", num, num * 10);
	return (0);
}

想定外の形式には対応できない

数値の入力に用いているscanf関数の第1引数に“%d”と記述し、入力された文字を10進数として扱うように指示していますが、これはあくまで『10進数として認識できる値が入力される』ことを前提としたものです。

このとき入力される値は、文字の並んだ文字列となります。例えば56という値も、キーボードから入力される段階では数値ではなく“56”という文字列です。scanf関数の第1引数に記述された“%d”によって、それが10進整数の「56」に変換されて第2引数以降の変数に格納されるのです。

scanf関数やprintf関数の引数に用いる“%d”のような記号を「変換指定子」と呼び、入力を受け取るscanf関数の場合は入力変換仕様に基づいて、入力された文字列(文字の並び)を適切なデータ型に変換するよう決められています。

しかし、変換指定子が対応していない形式の文字列が入力された場合の振る舞いについては、特に規定されていません。従って、10進整数を受け取りたい%dに対してAやら%やらの「10進整数ではない文字列」を入力した場合、その振る舞いは未定です ※1

「未定」とは無責任な表現ですが、要するに『処理系によって扱いは様々』だということです。そのため、Visual C++とLSI Cで結果が異なってしまったのです。

ここでは仕様を単純にするためにscanf関数をキーボードからの入力に用いていますが、本来scanf関数は入力元を切り替えるリダイレクトと併用し、ファイルや通信機器から一連のデータを連続して受け取る際に用います。その場合、ファイルや通信機器の側で送り出すデータの形式(フォーマット)が固定されているため、本文で取り上げているようなデータ型の違いによる問題は基本的には発生しません(発生しないように設計しなければなりません)

条件判定と分岐の構造

さて、ユーザーは気ままなものです。こちら(プログラマー)がいくら数値の入力を期待していても、AやらXやら%といった数値ではない値が入力されることがあるでしょう。そのような場合に、意味不明の数値を表示してはいけません。

0~9までの1桁の整数以外が入力されたら、本来の計算をせずにエラーメッセージを表示させるようにしてみましょう。そのためには、入力された値(上のソースでは変数numの保持している値)を調べなければなりません。そして、その値が0~9の範囲の整数だったら計算して結果を表示し、そうでなければメッセージを表示します。

このように変数の値を調べ、その結果によって異なる処理を行わせる形を「条件判定と分岐の構造」と呼び、ifを使って記述します。