付録 今回の補足
付録 C言語の仕組みとゲームプログラムの考え方
この付録では、第2回と第3回の途中で出てくる、少し引っかかりやすいC言語の仕組みをまとめます。
ゲームを完成させるために、すべてを暗記する必要はありません。
コードの意味が分からなくなったときに、このページへ戻って確認してください。
第2回で出てくるC言語の仕組み
1.文字と文字列は別のもの
C言語では、文字と文字列は別のものです。
char c = '3';
char text[] = "3";
| 書き方 | 意味 | メモリの中身 |
|---|---|---|
'3' |
1文字 | 文字コードを表す1つの値 |
"3" |
文字列 | '3'と終端文字'\0'の並び |
"1234" |
文字列 | '1'、'2'、'3'、'4'、'\0' |
1文字は、シングルクォーテーションで囲みます。
char number = '3';
文字列は、ダブルクォーテーションで囲みます。
char number[] = "3";
C言語には、文字列専用の特別な型がありません。
文字列は、char型の配列に文字を順番に並べ、最後に終端文字'\0'を入れたものです。
文字列 "3"
添え字 0 1
配列の中身 '3' '\0'
4文字の文字列を保存するとき、配列は最低5要素必要です。
最後の1要素を終端文字'\0'に使用します。
char input[5];
2.文字を==で比較できる理由
次のコードでは、2つの文字を==で比較しています。
if (input[i] == input[j])
{
return 3;
}
文字は、コンピュータの中では文字コードという整数値で扱われます。
今回使用しているVisual Studioの環境では、基本的な英数字はASCIIコードに対応した値になります。
| 文字 | ASCIIコード |
|---|---|
'0' |
48 |
'1' |
49 |
'2' |
50 |
'3' |
51 |
'A' |
65 |
例えば、次の比較は、内部では同じ整数値かどうかを調べています。
'3' == '3'
51 == 51
値が同じなので、比較結果は真になります。
input[i] == input[j]
も、2つの配列要素に保存された文字コードが同じかどうかを調べています。
文字列全体は==で比較しない
1文字どうしは==で比較できますが、文字列全体の比較には==を使いません。
if (input == answer) /* 文字列の内容比較には使わない */
{
}
文字列の内容を比較するときは、strcmp関数を使います。
#include <string.h>
if (strcmp(input, answer) == 0)
{
printf("正解です。\n");
}
strcmpの戻り値が0なら、2つの文字列の内容が同じです。
(自分で配列の中の文字列がすべて一致してるかどうか調べれば、strcmpを使わなくても比較できるよ。まぁあるものは使おうって話ではあるけど)
正確には、C言語の規格がすべての環境へASCIIコードの使用を強制しているわけではありません。
ただし、今回使用するVisual Studio環境の基本的な英数字はASCIIコードに対応しています。
3.関数の戻り値とは
関数は処理を実行したあと、呼び出した場所へ1つの値を返すことができます。
この値を戻り値といいます。
例えば、入力内容を確認する関数を次のように作れます。
int CheckInput(char input[])
{
if (strlen(input) != 4)
{
return 1;
}
/* 数字以外が含まれているか調べる */
/* 問題があれば return 2; */
/* 同じ数字が含まれているか調べる */
/* 問題があれば return 3; */
return 0;
}
この関数では、戻り値に意味を持たせています。
| 戻り値 | 意味 |
|---|---|
0 |
正しい入力 |
1 |
4桁ではない |
2 |
数字以外が含まれている |
3 |
同じ数字が含まれている |
呼び出す側では、戻り値を変数へ受け取ります。
int result;
result = CheckInput(input);
戻り値を調べることで、入力のどこに問題があったのか判断できます。
if (result == 1)
{
printf("4桁で入力してください。\n");
}
else if (result == 2)
{
printf("数字だけを入力してください。\n");
}
else if (result == 3)
{
printf("同じ数字を2回使わないでください。\n");
}
returnが実行されると関数はその場で終わる
次のコードで重複を見つけた場合、return 3;が実行されます。
if (input[i] == input[j])
{
return 3;
}
returnが実行されると、その関数はその場で終了します。
その後に書かれている比較処理は実行されず、呼び出し元へ3が返ります。
戻り値がない関数
呼び出し元へ値を返さない関数は、戻り値の型をvoidにします。
void MakeProblem(char answer[])
{
/* 問題を作る */
}
この関数は、問題を作る処理を行いますが、戻り値は返しません。
main関数の戻り値
return 0;
main関数の戻り値は、プログラムを呼び出したOSへ返されます。
一般に0は、プログラムが正常に終了したことを表します。
4..cと.cppでは何が違うのか
C言語のプログラムを.cppで保存しても、今回程度のコードであればコンパイルして動くことがあります。
main.c → C言語としてコンパイル
main.cpp → C++としてコンパイル
Visual Studioでは、主にファイルの拡張子から使用する言語モードを判断します。
| 拡張子 | 扱われる言語 |
|---|---|
.c |
C言語 |
.cpp |
C++ |
.cppでも動くのは、今回書いているC言語のコードの多くが、C++でも使用できる書き方だからです。
ただし、.cppで保存した時点で、C言語としてではなくC++としてコンパイルされます。
Visual Studioでは同じcl.exeが使われる場合でも、拡張子によってCモードとC++モードが切り替わります。
CとC++は似ていますが、完全に同じ言語ではありません。
- Cでは動くがC++ではエラーになるコードがある
- C++だけで使用できる機能がある
- エラーの判定や型の扱いが異なる場合がある
C言語の授業では、C言語として動作を確認するために.cで保存してください。
.cppで動いたからといって、C言語としてコンパイルされたとは限りません。
第3回で出てくるゲームプログラムの考え方
5.一度で終わるプログラム
C言語の最初の授業では、次のようなプログラムをよく作ります。
#include <stdio.h>
int main(void)
{
int a;
int b;
scanf("%d", &a);
scanf("%d", &b);
printf("%d\n", a + b);
return 0;
}
このプログラムは、次の順番で1回だけ動きます。
入力する
↓
計算する
↓
結果を表示する
↓
終了する
結果を1回表示したら、プログラムは終わります。
6.ゲームは処理を繰り返す
ゲームは、結果を1回表示しただけでは終わりません。
プレイヤーが遊んでいる間、何度も処理を繰り返します。
HIT&BLOWでは、正解するまで次の処理を繰り返します。
入力する
↓
HITとBLOWを判定する
↓
結果を表示する
↓
正解でなければ、もう一度入力する
C言語では、次のように書けます。
while (1)
{
/* 4桁を入力する */
/* HITとBLOWを数える */
/* 結果を表示する */
if (hit == 4)
{
break;
}
}
7.無限ループはゲームの繰り返し処理のもとになる
while (1)
{
}
条件の1は常に真なので、このwhile文は何度でも繰り返します。
このような処理を無限ループといいます。
「無限」と聞くと、間違ったプログラムのように感じるかもしれません。
しかし、終了条件を用意して使う無限ループは、ゲームでよく使われる考え方です。
if (hit == 4)
{
break;
}
breakを実行すると、繰り返し処理を終了できます。
リアルタイムゲームのフレーム処理
リアルタイムゲームでは、一般に次の処理を繰り返します。
while (gameRunning)
{
Input();
Update();
Draw();
}
入力を調べる
↓
ゲームの状態を更新する
↓
画面を描画する
↓
次のフレームへ
この1回分の処理を、ゲーム中に何度も繰り返します。
HIT&BLOWはscanfでプレイヤーの入力を待つため、リアルタイムゲームのフレーム処理そのものではありません。
しかし、ゲームが終了するまで入力・判定・表示を繰り返すという基本構造は共通しています。
無限ループには、必ず終了する方法を用意します。
終了条件がなければ、意図せずプログラムが終わらなくなります。
8.入力を促す文字列をプロンプトという
次の表示は、プレイヤーへ入力を促しています。
printf("重複しない4桁の数字を入力してください:");
このように、ユーザーへ入力を求めるために表示する文字列をプロンプトといいます。
次の表示だけでは、何を入力すればよいか分かりません。
>
入力の条件を具体的に書くと、操作方法が分かりやすくなります。
重複しない4桁の数字を入力してください:1234
良いプロンプトには、次の情報を含めます。
- 何を入力するのか
- どのような形式で入力するのか
- 使用できる文字や数値の範囲
- 入力を間違えた場合、次に何をすればよいか
例えば、入力エラーの後にも案内を表示します。
printf("同じ数字が含まれています。\n");
printf("重複しない4桁の数字を入力してください:");
コンソール画面にもUIがある
UIというと、ボタンや画像がある画面を想像しやすいですが、コンソール画面にもUIがあります。
- メニューを表示する
- 入力を促す
- 入力例を表示する
- エラーの原因を説明する
- 次に行う操作を伝える
これらはすべて、ユーザーがプログラムを操作するためのUIです。
プロンプトは、文字だけで作る最も基本的なUIの一つです。
9.戻り値・無限ループ・プロンプトを組み合わせる
入力処理では、ここまで説明した仕組みを組み合わせられます。
int result;
while (1)
{
printf("重複しない4桁の数字を入力してください:");
scanf("%254s", input);
result = CheckInput(input);
if (result == 0)
{
break;
}
else if (result == 1)
{
printf("4桁で入力してください。\n");
}
else if (result == 2)
{
printf("数字だけを入力してください。\n");
}
else if (result == 3)
{
printf("同じ数字を2回使わないでください。\n");
}
}
処理の流れは次のようになります。
プロンプトを表示する
↓
プレイヤーが入力する
↓
CheckInput関数が入力を調べる
↓
戻り値が0なら入力完了
↓
エラーなら理由を表示して、もう一度入力する
この短い処理の中に、次の考え方が入っています。
- プロンプトによる入力案内
- 関数の戻り値
if文による分岐while文による繰り返しbreakによるループの終了
今回のまとめ
- 文字と文字列は別のもの
- 文字は文字コードという整数値として扱われる
- 1文字どうしは
==で比較できる - 文字列全体の比較には
strcmpを使う - 関数は戻り値を1つ返せる
returnが実行されると、その場で関数が終了する.cはC言語、.cppはC++としてコンパイルされる.cppでも動く場合はあるが、C言語として動いているとは限らない- ゲームは終了するまで処理を繰り返す
- 無限ループはゲームループの基本的な考え方につながる
- 入力を促す文字列をプロンプトという
- コンソールの文字表示もUIの一部


No Comments