ここでは,キーボードからの入力方法の詳細を説明する.
#include <stdio.h>
が必要です.
キーボードから1文字入力し,変数に代入するには,getchar関数を用いる.
関数のプロトタイプは,int getchar();
#include <stdio.h>
int main(void)
{
char c = getchar();
printf("input char : ");
printf("%d\n", c);
return 0;
}
実行例: input char : a 97 input char : s 115
1文字+改行を入力すると,入力された文字の文字コードが表示される.
キーボードから1行(=改行まで)入力するには,gets関数を用いる(とされてきた).
関数のプロトタイプは,char *gets(char *buffer);であり,キー入力された文字をbufferに格納する.
ところが,このプロトタイプからも分かる通り,getsは,バッファを溢れさせることが可能なため,この関数の使用は推奨されないか,または使用できなくなっている.
代わりに,ファイル入出力で用いるfgets関数を用い,入力元を stdinと指定すれば良い.
または,char *gets_s(char *buffer, size_t bufsize);関数が利用可能な場合がある.
(この関数は,全ての処理系で利用できるわけではない).
#include <stdio.h>
int main(void)
{
const int N = 10; /* 入力バッファサイズ */
char buf[N]; /* 入力バッファ */
fgets( buf, N, stdin); /* bufのサイズを指定できる. stdin = キーボード */
/* 文字列を表示 */
printf("%s\n", buf);
/* バッファ内データを文字コードで表示 */
for(int i=0; i<N; i++) {
printf("%02x ", buf[i]);
}
return 0;
}
実行例1(上が入力,下が出力)
01234
01234
<- 改行コード
30 31 32 33 34 0a 00 ffffffd0 40 00
実行例2(上が入力,下が出力)
0123456789
012345678 <- N-1文字分,格納された
30 31 32 33 34 35 36 37 38 00
このように,入力バッファのサイズを超える入力は打ち切られるため,バッファがあふれることはない.
また,ヌル文字を代入するため,実際に入力できる文字数はバッファサイズ-1である.
もう一つ,改行コードがそのまま入力バッファに格納される点に注意.
scanf関数の使い方
単純な文字や文字列の入力だけではなく,入力された文字列を「数値」として格納したい場合や,書式を指定してキーボード入力を処理したい場合にはscanf関数を用いる.
scanf 関数は,printf 関数によく似ており,書式指定文字列に続けて変数を渡すのだが,
値を格納する変数の前に & をつける必要がある.
この記号は,変数のアドレスを取り出す演算子で,scanf関数に値を格納する「場所」を教えている.
したがって,元々アドレスを意味しているポインタ変数や配列名の場合は,& をつける必要がない.(というより,つけてはいけない!)
#include <stdio.h>
int main(void)
{
int a;
float b;
double c;
printf("a = ");
scanf("%d", &a); // ここは整数型
printf("b = ");
scanf("%f", &b); // ここは単精度実数型
printf("c = ");
scanf("%lf", &c); // ここは倍精度実数型
printf("a*a = %d \n", a*a);
printf("b*b = %f \n", b*b);
printf("c*c = %lf \n", c*c);
return 0;
}
キーボード入力の際に,1行で複数のデータを入力する方法である.
そのような場合は,
scanf関数の書式指定に複数の % 記号を並べる.
ただし,ユーザに書式通りに入力させるよう指示する必要がある.
#include <stdio.h>
int main(void)
{
int a, b;
printf("a b =? ");
scanf("%d %d", &a, &b); /* スペース区切りで整数を2つ入力させる */
printf("a = %d b = %d\n", a, b);
return 0;
}
実行例:(OK) a b =? 1 2 a = 1 b = 2 実行例:(NG) a b =? 1,2 a = 1 b = 0
scanfの戻り値
scanf関数のプロトタイプ宣言を見ていると,戻り値が整数であることがわかる.
戻り値はscanfが変換・代入に成功した変数の個数を表している.
書式の不一致など,何らかの原因で変数への代入に失敗すると,渡した変数の個数より少ない値が返される.
#include <stdio.h>
int main(void)
{
int a, b;
int ret; /* scanfの戻り値用 */
printf("a b =? ");
ret = scanf("%d %d", &a, &b); /* スペース区切りで整数を2つ入力させる */
printf("a = %d b = %d\n", a, b);
printf("ret = %d\n", ret);
return 0;
}
実行例:(OK) a b =? 100 200 a = 100 b = 200 ret = 2 実行例:(NG) a b =? 100,200 a = 100 b = 0 ret = 1 <-1つしか変換されなかったことが検出できる. a b =? 1 a a = 1 b = 256 ret = 1 <-1つしか変換されなかった. C:\Users\tatsuya>test a b =? a b a = 4264008 b = 256 ret = 0 <-2つとも数値として変換されなかった.
以下は文字列の入力方法のまとめである。 「文字,文字列」,「配列」を先に理解しておくと良い.
#include <stdio.h>
int main(void)
{
char str1[100];
char str2[100];
printf("Input string 1 :");
scanf("%s", str1);
printf("Input string 2 :");
scanf("%s", str2);
printf("str1 = %s \n", str1);
printf("str2 = %s \n", str2);
return 0;
}
この例では,文字列を2つ入力させている.
一見,なんの問題もないように見えるが,実行すると以下のような動作をする.
(問題のない例) Input string 1 :aaa Input string 2 :bbb str1 = aaa str2 = bbb (問題の発生する例) Input string 1 :aaa bbb Input string 2 :str1 = aaa str2 = bbb
問題の発生する例では,最初にスペースを含む文字列を入力すると,2回目のscanf入力は飛ばされてプログラムが終了してしまう.
この原因は,%sでは,入力している文字列にスペースが含まれると,そこで単語として区切られてしまい,文字列strにはスペース以前の文字しか代入されないからである.
つまり,aaa bbb(改行) というキー入力に対して,一旦,「入力バッファ」と呼ばれるメモリーに文字列が全部格納され,次にscanf関数が書式指定文字列を元に入力バッファの中身を解析をして,ここではスペース文字までの 「aaa」 のみが変数str1に代入される.
残りの「bbb」+「改行」 が入力バッファに残っている状態で,2回目のscanfが呼ばれ,もともと入力バッファに残っていた「bbb」が str2 に代入されてしまう.
ではどうすれば良いかというと,
#include <stdio.h>
int main(void)
{
char str1[100];
char str2[100];
printf("Input string 1 :");
scanf("%[^\n]%*c", str1);
printf("Input string 2 :");
scanf("%[^\n]%*c", str2);
printf("str1 = %s \n", str1);
printf("str2 = %s \n", str2);
return 0;
}
とすれば良い.
実行例: Input string 1 :aaa bbb Input string 2 :ccc ddd str1 = aaa bbb str2 = ccc ddd
ここで,%[^\n]%*c のうち, %[^\n]は改行コードまでの(スペースも含めた)文字を読み込むという意味であり,
%*cは,一文字(ここでは改行コードを)読み飛ばす,という動作を指示したことになる.
scanf()関数は,多くのC言語入門書の最初に登場するライブラリ関数だが,実はかなり高度で複雑な機能を持っている.
もう一つの方法として,ファイルから1行読み込むライブラリ関数fgets()を使用し,ファイルポインタとしてstdinを指定する方法がある.
stdinは標準入力=キーボードを表し,何もしなくても使用することができる.
#include <stdio.h>
int main(void)
{
char str1[100];
char str2[100];
printf("Input string 1 :");
fgets(str1, 100, stdin);
printf("Input string 2 :");
fgets(str2, 100, stdin);
printf("str1 = %s \n", str1);
printf("str2 = %s \n", str2);
return 0;
}
実行例: Input string 1 :aaa bbb Input string 2 :ccc ddd str1 = aaa bbb str2 = ccc ddd
この例では,改行まで含めてbufに入力される点が scanf() の例と異なる.