【C言語】「do-while 文」を「for 文」に書き直す方法

C言語

ようこそ、KiRiOのブログへ!

本記事では「新・明解C言語中級編」の自由課題について解説します。


自由課題のとおり、この参考書には解答が載っておりません。
そこで、本記事で私なりの解答を共有しますので、ぜひ解答の参考にしてみてください。

今回解説する課題は「演習1-8」で、課題内容は以下のとおりです。

演習1-8List 1-8do 文を for 文を用いて書き直したプログラムを作成せよ。

設計

まず初めに、List 1-8 のプログラムを以下に記します。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_STAGE 10

int main(void)
{
	int i;
	int stage;
	int no;
	int ans;
	int num[MAX_STAGE];

	srand(time(NULL));
	ans = rand() % 1000;

	puts("0〜999の整数を当ててください。");

	stage = 0;

	do
	{
		printf("残り%d回。いくつかな:", MAX_STAGE - stage);
		scanf("%d", &no);
		num[stage++] = no;

		if (no > ans)
		{
			puts("\aもっと小さいよ。");
		}
		else if (no < ans)
		{
			puts("\aもっと大きいよ。");
		}
	} while(no != ans && stage < MAX_STAGE);

	if (no != ans)
	{
		printf("\a残念。正解は%dでした。", ans);
	}
	else
	{
		printf("正解です。%d回で当たりましたね。\n", stage);
	}

	puts("--- 入力履歴 ---");
	for (i = 0; i < stage; i++)
	{
		if (num[i] != ans)
		{
			printf(" %2d : %4d %+4d\n", i + 1, num[i], num[i] - ans);
		}
		else
		{
			printf(" %2d : %4d % 4d\n", i + 1, num[i], num[i] - ans);
		}
	}

	return 0;
}

なお、上記プログラムは、入力履歴表示(48〜58行目)の部分で「入力値と正解値との差が0の場合のみ符号を付与しない」ように修正を加えています(演習1-7)。
詳細は下記ブログをご覧ください▼

【C言語】出力時の符号付与は printf() の"フラグ"で指定せよ
ようこそ、KiRiOのブログへ! 本記事では「新・明解C言語中級編」の自由課題について解説します。 自由課題のとおり、この参考書には解答が載っておりません。 そこで、本記事で私なりの解答を共有しますので、ぜひ解答の参考にしてみ...

本問の対象となっている doは、プログラム中の22〜36行目の部分にあたります。
この部分では、下記処理が行われています。

  1. プレイヤが数値を入力(残り回数もあわせて表示)
  2. 入力数値を入力履歴用配列に格納
  3. 入力値と正解値との大小比較を行い、結果を表示
  4. 入力値 ≠ 正解値」かつ「入力回数 < 最大入力回数」の間だけ繰り返す

この do 文をfor 文に書き直すためには、do 文で必要となるループ変数を見つける必要があります。
また、一般的にfor 文では、ループ変数に対して「初期化処理」「繰り返し条件」「繰り返し時処理」を記述する必要があります。

今回のdo 文の中では、変数として「MAX_STAGE」「ans」「no」「stage」が使用されていますが、「MAX_STAGE」と「ans」は定数です。
次に「no」ですが、「no != ans」を条件としてループが行われていますが、no そのものに対して何かしらの処理が行われているわけではありません。

最後に「stage」ですが、こちらも no と同様に「stage < MAX_STAGE」と、繰り返し条件として使用されています。
また、26行目にて「stage++」と 繰り返し処理が行われるたびに stage に対してインクリメントされています。
さらにdo 文の範囲外となりますが、20行目にて「stage = 0」と stage初期化されています。

以上より、for 文に書き直す際のループ変数は stage となります。
また、 do 文での繰り返し条件として「入力値 ≠ 正解値」がありましたが、こちらの処理はfor 文内で「『入力値 = 正解値』であればループを抜ける」となるように記述します。

設計は以上となります。

実装

それでは、設計内容をもとに実装していきます。
設計部分でも述べましたとおり、今回 for 文に書き直す際のループ変数は stageです。
そして「初期化処理」「繰り返し条件」「繰り返し時処理」は以下のようになります。

  • 初期化処理:stage = 0
  • 繰り返し条件:stage < MAX_STAGE
  • 繰り返し時処理:stage++

以上を実装したものが下記プログラムとなります(20〜38行目)。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_STAGE 10

int main(void)
{
	int i;
	int stage;
	int no;
	int ans;
	int num[MAX_STAGE];

	srand(time(NULL));
	ans = rand() % 1000;

	puts("0〜999の整数を当ててください。");

	for (stage = 0; stage < MAX_STAGE; stage++;)
	{
		printf("残り%d回。いくつかな:", MAX_STAGE - stage);
		scanf("%d", &no);
		num[stage] = no;

		if (no > ans)
		{
			puts("\aもっと小さいよ。");
		}
		else if (no < ans)
		{
			puts("\aもっと大きいよ。");
		}
		else
		{
			break;
		}
	}

	if (no != ans)
	{
		printf("\a残念。正解は%dでした。", ans);
	}
	else
	{
		printf("正解です。%d回で当たりましたね。\n", stage);
	}

	puts("--- 入力履歴 ---");
	for (i = 0; i < stage; i++)
	{
		if (num[i] != ans)
		{
			printf(" %2d : %4d %+4d\n", i + 1, num[i], num[i] - ans);
		}
		else
		{
			printf(" %2d : %4d % 4d\n", i + 1, num[i], num[i] - ans);
		}
	}

	return 0;
}

以上で完了となります。
プログラムを実行して、これまでと同じ数当てゲームとして機能しているか確認してみてください。

まとめ

それでは、本記事で説明した内容を以下にまとめます。

  1. for 文では処理を繰り返し行うためのループ変数が必要となる
  2. ループ変数に対しては以下の処理が必要となる
    • 初期化処理(例:i = 0、省略可)
    • 繰り返し条件(例:i < 10
    • 繰り返し時処理(例:i++、省略可)

ここまで、記事を読んでいただき、ありがとうございました。

最後に、今回取り上げた課題が記載されている本を紹介します。
今回扱った課題以外にも、様々なプログラム開発について記載されているため、この記事とあわせて読んでいただくと、より理解が深まると思います。


また、参考として以下の本もご紹介しておきます。

こちらもオススメです。2021年12月14日に最新版が発売されました!

それでは、また別の記事でお会いしましょう!

コメント

タイトルとURLをコピーしました