Nodachisoft Nodachisoft logo, Katana Sword Icon
  
@あまじ✎ 2018年6月30日に更新

第2章09 ユーザからの入力を受け付ける

第2章09 ユーザからの入力を受け付ける
イチからゲーム作りで覚えるC言語
第2章08 プログラムにコメントを書く : PREV
NEXT : 第2章10 論理演算(BOOL演算) :

この記事でやること

前回はプロジェクト「0060_comment」を新しく作り、コメントをソースコードに書き込む方法をお話をしました。

今回は、新しくプロジェクト「0070_inputkey」を作り、ユーザからの入力を受け付ける方法をお話します。入力の方法はたくさんありますので、基本的なものからお話します。

プレイヤーからの文字入力を受け付けるプログラム

ではではプレイヤーからの文字入力を取り扱うサンプルプログラムを作成してみましょう。

プロジェクト「0070_intputkey」を新しく用意し、プロジェクトに空の「Scanf_s.c」を追加し、下のソースコードをコピペして動かしてみましょう。

 
scanf.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");
}

コピペなりして、実行してみて下さい。

scanf.cの実行結果
プレイヤーの名前を入力してください。
半角で 11 文字、全角で 5 文字までです。
プレイヤーの名前 :

こんな結果になり、標準入力(Standard Input)からの文字列の入力を待つ状態になります。

[[ info|ワンポイント]] {um-yellow標準入力とは通常はキーボードからの入力のことです。 ついでに、標準出力(Standard Output) とは通常はコンソール画面のことです。 文字がコンソール上に表示されるとき、標準出力されています。この用語はC言語に限らず使われています。

では、この状態でなにかキーボードで入力してみましょう。 「プレイヤーの名前 : 」の右側にキーボードから入力した文字がそのまま表示されると思います。文字を入れてエンターキーで完了します。

ためしに、「ぷらんく」と入れると、以下のようにプログラムの続きが実行されます。

scanf.cの実行結果
プレイヤーの名前を入力してください。
半角で 11 文字、全角で 5 文字までです。
プレイヤーの名前 : ぷらんく
+------[ステータス]------+
|      名前 : ぷらんく   |
+------------------------+

ステータスの欄にちゃんと「ぷらんく」が表示されています!

ではでは、一行づつソースコードを見ていってみましょう!

char型で文字列の領域の確保

3行目では char型で playerName という配列の変数を宣言しています。

※配列については少し前のページ(コチラ)でお話してます。

 
scanf.c
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_s.c
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 関数でよく使う変換指定子

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 関数でちゃんと変数に入力できたかの確認

ゲームプレイヤーはいろいろな文字をキーボード入力できちゃいますので、ちゃんとこちらが想定した入力がされたのかをチェックする必要があります。このチェックをちゃんとしないと、バグの元になったりします。

想定外の回答の入力 想定外の回答の入力

例えばチェックする内容としては・・

文字列の入力の場合のチェック

  • 文字数はあってる?文字が少なすぎてないか、多すぎてないか
  • 入力された各文字はOKなものか。例えばおかしな記号が入力されてないか。
  • 日本語などのワイド文字はいれられてもOKか。
  • 大文字、小文字などの制限はなくてOKか。

数字の入力の場合のチェック

  • 数値の範囲はOKか。
  • 数値でない文字(英文字や記号、空白)などが入っていないか。

全般的なチェック

  • そもそもちゃんと入力がされたか。

などがいろいろなチェックがありそうですね。

scanf で入力できたか確認

「そもそもちゃんと入力がされたか。」について補足としてお話しようと思います。

下のように書くと、scanf 関数で何個の入力を読み取ることができたかの結果を数字で取得できます。

 
scanf関数の結果を取得するサンプル1
int kazu;
int nyuuryoku;
kazu = scanf("%d", &nyuuryoku );

このサンプルでは、ちゃんと数字を入力したとき、結果として1つの数字を変数 nyuuryoku に代入できたため、変数 kazu に結果の 1 が入ります。

そして、数字以外の、記号や文字列などを入力してみると、ちゃんと変数に入力できなかったので、kazu に結果の 0 が入ります。

ちょっと唐突に式がでてきましたが、右辺の scanf 関数の結果が整数 1 となり、変数 kazu に代入されています。

関数の結果を取得する例
変数 = 関数(引数);

このような書き方で、変数に 右辺の関数の戻り値 の結果を代入することができます。関数がだす結果を「関数の戻り値」と呼びます。 「戻り値」は「もどりち」と読みます。

「かえりち」とは読まないので要注意 です。

ワンポイント 関数について、あらかじめ用意された printf や scanf などを使ったり、自分で新しい関数を作ったりもできます。 関数についての詳しい話はまた別のページでお話しようと思いますので、ここでは関数の戻り値を変数に入れることができる、とだけ理解してもらえればと思います。 同じように、数字を入力させたいのに文字が入れられてしまった場合でも同じように、「ちゃんと数字が入ったのか」のか、結果を見ることができます。

 
scanf関数の結果を取得するサンプル2
int kazu;
int nyuuryoku;
kazu = scanf("%d", &nyuuryoku );

たとえば、このサンプルで数字「123」といれると、変数 nyuuryoku に整数 123 が代入され、無事に1つ変数に代入ができたので scanf 関数の戻り値は 1 となり、変数 kazu に 1 が入ります。

でも数字ではなく、ここで イジワルな人が「あいうえお」なんて入れると、整数ではないので、ちゃんと変数 nyuuryoku に代入できず、 scanf 関数の戻り値は 0 となります。

scanf 関数の戻り値の使い方は?

変数に代入したいのに、戻り値が 0 だったら、ちゃんと思った通りに入力されていないので、もう一度 scanf 関数を呼び出して、入力がうまくいくまで繰り返し入力を求める、なんていう処理にすることができます。

そういった繰り返しの処理などや、"もし戻り値が 0 だったら" という if の処理は、後のページでまたお話しますね。

scanf でよくあるバグ

scanf 関数で以下のようにプログラムすると、文字列を入力できます。

バグあり.c
#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型配列 , 入力サイズ);

の形式で使うことができ、下のコードのように、入力する桁を明記できます。

 
use_gets_s.c
#include <stdio.h>
int main(){
  char playername[12];
  if( gets_s(buff, 12== NULL{
    // 入力がうまくいってない場合
    printf("入力エラーです!\n");
  } else {
    printf("プレイヤー名:%s\n", buff);
  }
}

おまけ。Microsoft 仕様の他の文字入力に使う関数

scanf_s 関数

scanf_s 関数は Microsoft のビルド環境で使える、安全な文字入力用の関数です。

scanf_s( 書式指定文字列  , 文字列変数, 入力を受け付ける文字列の最大バイト数 );

で書くことが出来ます。

プレイヤー名を入力するなら、下のようなコードになります。

バグあり.c
#include <stdio.h>
int main(){
    char playername[12];
    scanf_s("%s", playername, 12);
}

今回は関数の第3引数に12を指定しているので、 12 バイトまでの入力を受け付けます。

scanf_s 関数で 2個 の変数への代入をする方法

scanf_s 関数では同時に複数個の変数への代入をすることができます。

例えば、2個の文字列と 1 個の整数を入力するにはこのように書きます。

Scanf_s関数で複数個の変数への代入サンプル
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」(□は半角スペース) と入力すると、変数はそれぞれ下のように代入されます。

  • 変数 name に文字列「ぷらんく」
  • 変数 sukina_tabemono に文字列「白きのこ」
  • 変数 tairyoku に整数 1

そして、3 つの変数が無事に入力されたので、scanf_s 関数の結果として 3 が得られます。

変数 kazu には 3 が代入されることになります。

scanf_s 関数で「ちゃんと入力された文字列の数」を取得

例えば、11 桁までのプレイヤー名を求めるコードで、12桁の「123456789012」と入力したとします。でも scanf_s 関数で 11 文字までしか入らないよう制限をかけています。この時どうなるでしょうか?

scanf_s.c
#include <stdio.h>
int main(){
    char playername[12];
    printf("プレイヤーの名前:");
    scanf_s("%s", playername, 12);
    printf("名前:%s", playername);
}

結果は下のようになります。

scanf_s.cの実行結果
プレイヤーの名前 : 123456789012
名前:

名前の欄になにも表示されていませんね。 指定した文字を超えた場合は、変数には空文字 が代入 されます。

空文字は '\0' だけが入っている文字列で、 "" とも書けます。

scanf 関数で桁数制限したときは、ちゃんと指定した桁の入力が出来ているので、ちょっと結果が違いますね。

セキュリティのために使ってはダメな関数

入力を受け取る昔からある関数に gets() 関数がありますが、これは バッファーオーバーフローを起こしてしまう可能性があるので絶対使わないでください、 と US-CERT でも注意喚起されています。gets_s 関数で安全に入力をするようにしましょー。

あとがき

C言語で文字を入力する方法は他にもいろいろな方法があります。

今回記載したものは「エンター」キーを入力しないと、次に進まないような関数のみですが、

ゲームではキーボード入力したら即座にゲームへ反映されるかと思います。

そのような場合に使う入力用の仕組みは後ほど解説していこうと思います。

非常に参考になったサイトさまや、参考文献など

ページの更新履歴

更新日 更新内容
2021.02.11 scanf_s が Microsoft Visual Studio 系のビルド環境で定義されており、標準仕様からは外れていることを追記。gets_s について追記。

イチからゲーム作りで覚えるC言語
第2章08 プログラムにコメントを書く : PREV
NEXT : 第2章10 論理演算(BOOL演算) :
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

第1章01 Visual Studio Community 2019 のインストール手順

第1章01 Visual Studio Community 2019 のインストール手順

#C11仕様#C言語#ゲームプログラミング✎ 2021-08-08
C言語でプログラミングをするために、無料で使える Visual Studio Community を使った開発環境を揃えていく手順や注意点をお話しています。
目次
第2章09 ユーザからの入力を受け付ける
第2章09 ユーザからの入力を受け付ける
この記事でやること
この記事でやること
プレイヤーからの文字入力を受け付けるプログラム
プレイヤーからの文字入力を受け付けるプログラム
char型で文字列の領域の確保
char型で文字列の領域の確保
キーボードからの入力文字列を文字列変数に代入
キーボードからの入力文字列を文字列変数に代入
scanf 関数でよく使う変換指定子
scanf 関数でよく使う変換指定子
scanf 関数でちゃんと変数に入力できたかの確認
scanf 関数でちゃんと変数に入力できたかの確認
scanf で入力できたか確認
scanf で入力できたか確認
scanf 関数の戻り値の使い方は?
scanf 関数の戻り値の使い方は?
scanf でよくあるバグ
scanf でよくあるバグ
ご参考:安全にキーボード入力を受け付ける関数
ご参考:安全にキーボード入力を受け付ける関数
おまけ。Microsoft 仕様の他の文字入力に使う関数
おまけ。Microsoft 仕様の他の文字入力に使う関数
scanf_s 関数
scanf_s 関数
scanf_s 関数で 2個 の変数への代入をする方法
scanf_s 関数で 2個 の変数への代入をする方法
scanf_s 関数で「ちゃんと入力された文字列の数」を取得
scanf_s 関数で「ちゃんと入力された文字列の数」を取得
セキュリティのために使ってはダメな関数
セキュリティのために使ってはダメな関数
あとがき
あとがき
非常に参考になったサイトさまや、参考文献など
非常に参考になったサイトさまや、参考文献など
ページの更新履歴
ページの更新履歴
Nodachisoft © 2021