
前回はプロジェクト「0060_comment」を新しく作り、コメントをソースコードに書き込む方法をお話をしました。
今回は、新しくプロジェクト「0070_inputkey」を作り、ユーザからの入力を受け付ける方法をお話します。入力の方法はたくさんありますので、基本的なものからお話します。
ではではプレイヤーからの文字入力を取り扱うサンプルプログラムを作成してみましょう。
プロジェクト「0070_intputkey」を新しく用意し、プロジェクトに空の「Scanf_s.c」を追加し、下のソースコードをコピペして動かしてみましょう。
#include <stdio.h>
int main(void) {
char playerName[12];
printf("プレイヤーの名前を入力してください。\n");
printf("半角で 11 文字、全角で 5 文字までです。\n");
printf("プレイヤーの名前 : ");
// キーボードからの入力を求める
scanf("%11s", playerName, 12);
// プレイヤーのステータスを表示
printf("+------[ステータス]------+\n");
printf("|%10s : %-11s|\n", "名前", playerName);
printf("+------------------------+\n");
}
コピペなりして、実行してみて下さい。
プレイヤーの名前を入力してください。
半角で 11 文字、全角で 5 文字までです。
プレイヤーの名前 :
こんな結果になり、標準入力(Standard Input)からの文字列の入力を待つ状態になります。
[[ info|ワンポイント]] {um-yellow標準入力とは通常はキーボードからの入力のことです。 ついでに、標準出力(Standard Output) とは通常はコンソール画面のことです。 文字がコンソール上に表示されるとき、標準出力されています。この用語はC言語に限らず使われています。
では、この状態でなにかキーボードで入力してみましょう。 「プレイヤーの名前 : 」の右側にキーボードから入力した文字がそのまま表示されると思います。文字を入れてエンターキーで完了します。
ためしに、「ぷらんく」と入れると、以下のようにプログラムの続きが実行されます。
プレイヤーの名前を入力してください。
半角で 11 文字、全角で 5 文字までです。
プレイヤーの名前 : ぷらんく
+------[ステータス]------+
| 名前 : ぷらんく |
+------------------------+
ステータスの欄にちゃんと「ぷらんく」が表示されています!
ではでは、一行づつソースコードを見ていってみましょう!
3行目では char型で playerName という配列の変数を宣言しています。
※配列については少し前のページ(コチラ)でお話してます。
char playerName[12];
playerName には配列として 12 個の char 型の変数を確保しているので、12文字(12バイト)を格納できます。ただし、文字列は最後に NULL終端文字('\0')が必要ですので、実際に使える文字は半角で 11 文字(11バイト)です。
日本語は 1 文字で 2 バイトとられるものがほとんどなので、11 ÷ 2 = 5 余り 1 ということで日本語は5文字までということを書いています。
[[ info|ワンポイント]]
プログラム内の"全角で5文字まで"は日本語版Windows のコマンドプロンプトを使用してのデフォルト設定を前提にしています。
前のページ
でchar型を扱うとき、ASCIIコード表を使っての1文字と数値の変換と、日本語は1バイトに収まらないものが多いという話をしたかと思います。
こういった数値と文字の変換ルールは「文字コード」というもので定義されています。
OSが日本語版Windows なら、コマンドプロンプトは通常 Shift-JIS と呼ばれる文字コードの一種である「Windows31j」が使われています。
Window31j は別名 CP932、MS932とか呼ばれることがあります。
Shift-JISでは日本語は半角カタカナなどの一部は1バイト、通常は2バイトが1文字あたりに必要となります。
9行目で、プレイヤーからのキーボード入力を受け付けて変数に代入する、新しい関数 scanf が登場しています。
scanf("%11s", playerName );
scanf 関数をこのように書くと、 文字列変数 playerName にキーボード(標準入力)から入力した文字列を代入することができます。
scanf( 書式指定文字列 , 文字列変数 );
今回は関数の第1引数に「%11s」と書式を指定しており、 11 バイトまでの文字列入力を受け付けます。
ここで注意ですが、 キーボードからコンソール画面に文字を入力してエンターキーを押したとき、最後に'\n'(エンターキーを推した時の改行を表す文字コード)を含めた状態で文字列がコンソールから scanf 関数に送られます。
scanf 関数でコンソールから文字列が送られてきたとき、1文字1文字を playnerName にコピーしていきますが、その時 '\n' があったらコンソールから送られた文字列の最後と判断しています。ですので、入力できる文字列は 11バイト + '\n'(改行コード)となりますので、11文字までが実際の入力できる文字数です。
scanf の書式指定文字列は、printf と似ていて、%s や %d などの変換指定子を指定できます。printf では文字を出力するために整数などのデータから文字への変換をしていましたが、scanf では変数に代入するためにコンソールからの文字列をデータ(文字列や整数)に変換する機能を持ちます。
scanf 関数では文字列以外にも、整数や小数を書いた文字列を、データ(int型や double 型)に変換する機能があります。よく使うこういった入力のための変換指定子ものを例をつけてまとめておきます。
よく使われる入力変換指定子と使い方の例
処理 | 記号 | 例 |
---|---|---|
文字列を入力 | %s | char message[10]; scanf("%9s", message, 10); 9 文字までの入力を指定しています。 |
整数を入力 | %d | int answer; scanf("%d", &answer); ※変数名の頭に「&」記号を付ける必要があります。 |
long型に整数を入力 | %ld | int answer; scanf("%ld", &answer); |
float型に小数を入力 | %f | float taion; scanf("%f", &taion); |
double型に小数を入力 | %lf | double kyori; scanf("{impg}%lf", &kyori); |
ゲームプレイヤーはいろいろな文字をキーボード入力できちゃいますので、ちゃんとこちらが想定した入力がされたのかをチェックする必要があります。このチェックをちゃんとしないと、バグの元になったりします。
想定外の回答の入力
例えばチェックする内容としては・・
文字列の入力の場合のチェック
数字の入力の場合のチェック
全般的なチェック
などがいろいろなチェックがありそうですね。
「そもそもちゃんと入力がされたか。」について補足としてお話しようと思います。
下のように書くと、scanf 関数で何個の入力を読み取ることができたかの結果を数字で取得できます。
int kazu;
int nyuuryoku;
kazu = scanf("%d", &nyuuryoku );
このサンプルでは、ちゃんと数字を入力したとき、結果として1つの数字を変数 nyuuryoku に代入できたため、変数 kazu に結果の 1 が入ります。
そして、数字以外の、記号や文字列などを入力してみると、ちゃんと変数に入力できなかったので、kazu に結果の 0 が入ります。
ちょっと唐突に式がでてきましたが、右辺の scanf 関数の結果が整数 1 となり、変数 kazu に代入されています。
変数 = 関数(引数);
このような書き方で、変数に 右辺の関数の戻り値 の結果を代入することができます。関数がだす結果を「関数の戻り値」と呼びます。 「戻り値」は「もどりち」と読みます。
「かえりち」とは読まないので要注意 です。
ワンポイント 関数について、あらかじめ用意された printf や scanf などを使ったり、自分で新しい関数を作ったりもできます。 関数についての詳しい話はまた別のページでお話しようと思いますので、ここでは関数の戻り値を変数に入れることができる、とだけ理解してもらえればと思います。 同じように、数字を入力させたいのに文字が入れられてしまった場合でも同じように、「ちゃんと数字が入ったのか」のか、結果を見ることができます。
int kazu;
int nyuuryoku;
kazu = scanf("%d", &nyuuryoku );
たとえば、このサンプルで数字「123」といれると、変数 nyuuryoku に整数 123 が代入され、無事に1つ変数に代入ができたので scanf 関数の戻り値は 1 となり、変数 kazu に 1 が入ります。
でも数字ではなく、ここで イジワルな人が「あいうえお」なんて入れると、整数ではないので、ちゃんと変数 nyuuryoku に代入できず、 scanf 関数の戻り値は 0 となります。
変数に代入したいのに、戻り値が 0 だったら、ちゃんと思った通りに入力されていないので、もう一度 scanf 関数を呼び出して、入力がうまくいくまで繰り返し入力を求める、なんていう処理にすることができます。
そういった繰り返しの処理などや、"もし戻り値が 0 だったら" という if の処理は、後のページでまたお話しますね。
scanf 関数で以下のようにプログラムすると、文字列を入力できます。
#include <stdio.h>
int main(){
char playername[12];
scanf("%s", playername);
}
このようなプログラムで、12 文字以上を入力すると、文字列の終わりを表す、終端文字列('\0') を含めて、13 文字が必要となり、変数 playername で使えるメモリサイズを超えてしまいます。 これはバグを引き起こす可能性があり、特にメモリサイズを超えてしまうバグをバッファーオーバーフローと呼びます。
このページではキーボード(標準入力)からの入力を受け付けるために scanf 関数という関数を使いました。 scanf 関数でも気を付けてフォーマットの識別子に、入力する桁を指定すれば、バッファーオーバーフローを防ぐことが出来ますが、ちゃんと入力できる長さ上限を意識してプログラムを書く必要があります。
この例であれば、scanf のい第一引数に "%11s" と書いて、 11 桁までを入力できることを提示してあげることが重要です。こう書いておけば、もし 12 桁以上が入力されたとき、切り捨てされます。
C11 仕様以降(2011年に制定された C言語の仕様) では、scanf 関数以外に gets_s 関数が使えます。
gets_s ( char型配列 , 入力サイズ);
の形式で使うことができ、下のコードのように、入力する桁を明記できます。
#include <stdio.h>
int main(){
char playername[12];
if( gets_s(buff, 12)== NULL){
// 入力がうまくいってない場合
printf("入力エラーです!\n");
} else {
printf("プレイヤー名:%s\n", buff);
}
}
scanf_s 関数は Microsoft のビルド環境で使える、安全な文字入力用の関数です。
scanf_s( 書式指定文字列 , 文字列変数, 入力を受け付ける文字列の最大バイト数 );
で書くことが出来ます。
プレイヤー名を入力するなら、下のようなコードになります。
#include <stdio.h>
int main(){
char playername[12];
scanf_s("%s", playername, 12);
}
今回は関数の第3引数に12を指定しているので、 12 バイトまでの入力を受け付けます。
scanf_s 関数では同時に複数個の変数への代入をすることができます。
例えば、2個の文字列と 1 個の整数を入力するにはこのように書きます。
int kazu;
char name[20];
char sukina_tabemono[21];
int tairyoku;
kazu = scanf_s("%s %s %d", name, 20, sukina_tabemono , 21 , &tairyoku);
scanf_s の一つ目の引数に "%s %s %d" と書いてありますね。
これで、「文字列1 文字列2 整数」と入力することで一度に三つの入力を変数に代入することができます。 文字列と文字列の間にスペースやタブがあると、区切りと見なされます。 例えば上のサンプルで「ぷらんく□白きのこ□□1」(□は半角スペース) と入力すると、変数はそれぞれ下のように代入されます。
そして、3 つの変数が無事に入力されたので、scanf_s 関数の結果として 3 が得られます。
変数 kazu には 3 が代入されることになります。
例えば、11 桁までのプレイヤー名を求めるコードで、12桁の「123456789012」と入力したとします。でも scanf_s 関数で 11 文字までしか入らないよう制限をかけています。この時どうなるでしょうか?
#include <stdio.h>
int main(){
char playername[12];
printf("プレイヤーの名前:");
scanf_s("%s", playername, 12);
printf("名前:%s", playername);
}
結果は下のようになります。
プレイヤーの名前 : 123456789012
名前:
名前の欄になにも表示されていませんね。 指定した文字を超えた場合は、変数には空文字 が代入 されます。
空文字は '\0' だけが入っている文字列で、 "" とも書けます。
scanf 関数で桁数制限したときは、ちゃんと指定した桁の入力が出来ているので、ちょっと結果が違いますね。
入力を受け取る昔からある関数に gets() 関数がありますが、これは バッファーオーバーフローを起こしてしまう可能性があるので絶対使わないでください、 と US-CERT でも注意喚起されています。gets_s 関数で安全に入力をするようにしましょー。
C言語で文字を入力する方法は他にもいろいろな方法があります。
今回記載したものは「エンター」キーを入力しないと、次に進まないような関数のみですが、
ゲームではキーボード入力したら即座にゲームへ反映されるかと思います。
そのような場合に使う入力用の仕組みは後ほど解説していこうと思います。
更新日 | 更新内容 |
---|---|
2021.02.11 | scanf_s が Microsoft Visual Studio 系のビルド環境で定義されており、標準仕様からは外れていることを追記。gets_s について追記。 |
コメント、ありがとうございます。
ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。
Twitter:@NodachiSoft_jpお名前:以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください
お名前: