C言語の基本|scanfでキーボード入力する

キャッチコピー:キーボードから受け取った値で、C言語のプログラムを「表示するだけ」から「対話できる」プログラムへ進化させよう。

これまで printf を使って文字や数値を画面に表示してきたなら、次に覚えたいのがキーボードから値を入力する方法です。

画面へ情報を出すだけのプログラムでは、実行するたびにほぼ同じ処理を行います。しかし、ユーザーが入力した値をプログラムの中へ取り込めるようになると、その値によって計算したり、処理を変えたりできるようになります。

C言語でキーボードから入力された値を受け取る代表的な方法が、scanf関数です。

scanfを使えるようになると、たとえば次のようなプログラムへ発展させられます。

  • キーボードから入力した数値を使って計算する
  • 入力された文字によって処理を変える
  • 入力した値を画面へ表示して確認する

ただし、scanfにはprintfとは少し異なる書き方があります。

特に最初のうちは、

  • %dや%cなどの変換指定
  • 変数の前に付ける&
  • 入力したデータと変数の型の関係

といった部分で戸惑いやすいでしょう。

ここでは、一度に難しいことを覚えようとせず、scanfがどのようにキーボード入力を変数へ格納するのかを順番に見ていきます。

scanf関数とは

scanfは、標準入力からデータを読み取り、指定した変数へ格納するための関数です。

一般的なコンソールプログラムでは、標準入力としてキーボードが使われます。

たとえばユーザーがキーボードから10と入力したとします。

scanfで10進整数として読み取るよう指定しておけば、入力された10をint型の変数へ格納できます。

一方、Aと入力した場合でも、scanfにどの変換指定を使うかによって意味が変わります。

  • %cならAという1文字として読み取る
  • %xならAという16進数として読み取る

このようにscanfでは、入力された文字列をどの形式のデータとして解釈するかが大切です。

図1:キーボードからscanfを通して変数へ値が入る流れ

この図から分かること

scanfは、キーボードから入力されたデータをそのまま適当に変数へ入れているわけではありません。

まず入力されたデータを読み取り、%dや%cなどの変換指定に従ってデータを解釈します。そして、指定された変数の場所へ値を書き込みます。

つまり、

キーボード入力 → scanfによる読み取り → 変換指定による解釈 → 変数へ格納

という流れになっています。

scanfを使うための準備

scanfは標準入出力を扱う関数です。

そのため、printfと同じようにstdio.hをインクルードします。

#include <stdio.h>

printfを使うプログラムですでに何度も登場しているため、scanfを使う場合も同じ準備をすると覚えておくと分かりやすいでしょう。

たとえば、scanfとprintfを両方使うプログラムなら、先頭は次のようになります。

#include <stdio.h>

int main(void)
{
    /* ここにprintfやscanfを使った処理を書く */

    return 0;
}

scanfの基本の形

scanfは基本的に次の形で使用します。

scanf("変換指定", &変数名);

たとえば、int型の変数valueへ10進整数を入力する場合は次のようになります。

int value;

scanf("%d", &value);

このscanfには、大きく分けて2つの重要な情報があります。

部分役割
%d入力されたデータをどの形式として読み取るか指定する
&value読み取った値をどの変数へ格納するか指定する

scanfを理解するときは、まずこの2つを分けて考えると分かりやすくなります。

変換指定で入力データの読み方を決める

scanfでは、入力されたデータをどのようなデータとして解釈するのかを変換指定で指定します。

代表的なものを見てみましょう。

変換指定読み取り方入力先となる変数の型の例
%d10進整数として読み取るint
%c1文字として読み取るchar
%x16進整数として読み取るunsigned int
%lf浮動小数点数として読み取るdouble

たとえば、次のscanfでは入力を10進整数として読み取ります。

scanf("%d", &value);

次のscanfでは1文字として読み取ります。

scanf("%c", &ch);

そして次の場合は、入力を16進数として読み取ります。

scanf("%x", &hex_value);

同じ文字をキーボードから入力したとしても、どの変換指定を使用するかによって解釈される意味が変わるところが重要です。

変数のアドレスと&の役割

scanfで初心者が特に戸惑いやすいのが、変数名の前に付いている&です。

たとえば次のコードを見てください。

int value;

scanf("%d", &value);

printfで変数valueの内容を表示するときは、次のように変数名をそのまま指定できます。

printf("%d\n", value);

ところがscanfでは次のようになっています。

scanf("%d", &value);

valueではなく、&valueとなっています。

C言語では変数名の前に&を付けることで、その変数が置かれているメモリ上のアドレスを取得できます。

アドレスとは、簡単に考えると変数が置かれている場所を示す住所のようなものです。

なぜscanfには変数のアドレスが必要なのか

scanfの仕事は、入力された値を変数へ書き込むことです。

たとえば次のコードを考えてみます。

int value;

scanf("%d", &value);

ユーザーが25と入力した場合、scanfは25という値を読み取るだけではありません。

その25をvalueへ書き込む必要があります。

イメージとしては次のようになります。

キーボードから25を入力
        ↓
scanfが25を読み取る
        ↓
&valueでvalueの場所を確認
        ↓
その場所へ25を書き込む
        ↓
valueの値が25になる

scanfから見ると、値を書き込むためにはどこへ書けばよいのかが分からなければなりません。

そこで&valueによって、

「valueはこの場所にあります」

という情報をscanfへ渡しています。

最初は&を不思議に感じるかもしれませんが、

scanfは変数へ値を書き込むので、書き込み先の住所が必要

と考えると理解しやすくなります。

同じAでも%cと%xでは意味が違う

scanfの特徴を理解するうえで、とても分かりやすいのが%cと%xの比較です。

キーボードから同じAを入力してみましょう。

%cを使った場合は、

scanf("%c", &ch);

Aを1文字のデータとして読み取ります。

一方、%xを使った場合は、

scanf("%x", &hex_value);

Aを16進数として読み取ります。

16進数では、Aは10を表します。

したがって同じAという入力でも、

入力scanfの変換指定解釈
A%c文字A
A%x16進数A、つまり10

となります。

見た目が同じAでも、scanfにどのように読ませるかによって意味が変わるわけです。

図2:同じAを%cと%xで読み取ったときの違い

この図から分かること

キーボードから入力される文字が同じAでも、scanfがどの変換指定を使用するかによって処理結果は変わります。

%cならAを1文字として扱います。

A
↓
%c
↓
文字A

%xならAを16進数の数字として扱います。

A
↓
%x
↓
16進数のA
↓
10進数では10

scanfでは、入力された見た目だけではなく、変換指定が入力データの意味を決めるということが分かります。

実際に%cと%xを比較してみよう

ここまでの内容を1つのプログラムで確認してみましょう。

同じAを2回入力し、最初は%c、次は%xで読み取ります。

元の例とは変数名や表示内容を変更し、文字入力と16進数入力の違いを確認できるプログラムにしています。

文字入力と16進数入力を比較するプログラム

ファイル名:5_7_1.c

#include <stdio.h>

int main(void)
{
    char input_char;
    unsigned int input_hex;

    /* 入力された1文字を読み取る */
    printf("文字を1つ入力してください(例:A)> ");
    scanf("%c", &input_char);

    printf("文字を数値として表示すると: %d\n", input_char);

    /* 入力された値を16進数として読み取る */
    printf("\n16進数を入力してください(例:A)> ");
    scanf("%x", &input_hex);

    printf("16進数として読み取った値を10進数で表示すると: %u\n",
           input_hex);

    return 0;
}
実行結果の例
文字を1つ入力してください(例:A)> A
文字を数値として表示すると: 65

16進数を入力してください(例:A)> A
16進数として読み取った値を10進数で表示すると: 10

この実行例では、どちらもユーザーがAを入力しています。

しかし結果は、

65

10

になっています。

同じAを入力したにもかかわらず結果が異なるのは、1回目と2回目でscanfの変換指定が違うからです。

プログラムの変数を確認する

最初に2つの変数を宣言しています。

char input_char;
unsigned int input_hex;

input_charは、%cで読み取った1文字を格納するためのchar型変数です。

input_hexは、%xで読み取った16進整数を格納するためのunsigned int型変数です。

対応関係は次のようになります。

変数使用する変換指定役割
input_charchar%c1文字を格納する
input_hexunsigned int%x16進整数を格納する

scanfでは、変換指定だけを覚えるのではなく、変換指定と変数の型を組み合わせて覚えることが大切です。

1回目の入力を詳しく見てみよう

最初に次のprintfを実行します。

printf("文字を1つ入力してください(例:A)> ");

画面には次のように表示されます。

文字を1つ入力してください(例:A)>

その直後にscanfがあります。

scanf("%c", &input_char);

%cなので、入力されたデータを1文字として読み取ります

ここでAを入力すると、input_charには文字Aが格納されます。

処理の流れは次のようになります。

キーボードからAを入力
        ↓
scanf("%c", &input_char)
        ↓
%cなので1文字として読み取る
        ↓
input_charへ文字Aを格納

なぜ文字Aを表示すると65になるのか

次のprintfでは、input_charを%dで表示しています。

printf("文字を数値として表示すると: %d\n", input_char);

input_charに入っているのは文字Aです。

コンピュータ内部では文字も数値に対応付けて扱われています。

一般的なASCIIを使用する環境では、大文字のAに対応する値は65です。

そのため、この例では次のように表示されます。

文字を数値として表示すると: 65

ここで大切なのは、

scanfが65を入力したわけではない

という点です。

ユーザーが入力したのはAです。

入力
A
↓
%cで1文字として読み取る
↓
input_charに文字Aを格納
↓
%dで数値として表示
↓
65

%cは文字として読み取るための変換指定です。

その文字をprintfの%dで数値として表示したため、この例では65が表示されています。

2回目の入力を詳しく見てみよう

続いて、次のscanfを実行します。

scanf("%x", &input_hex);

今度の変換指定は%xです。

%xは、入力されたデータを16進整数として読み取るための変換指定です。

ここでもAを入力してみます。

16進数では、数字は次のように進みます。

16進数10進数
00
11
22
99
A10
B11
C12
D13
E14
F15

したがって、16進数のAは10進数では10です。

処理の流れは次のようになります。

キーボードからAを入力
        ↓
scanf("%x", &input_hex)
        ↓
%xなので16進数として読み取る
        ↓
16進数Aを数値10として解釈
        ↓
input_hexへ10を格納

その後、次のprintfを実行しています。

printf("16進数として読み取った値を10進数で表示すると: %u\n",
       input_hex);

%uでunsigned int型のinput_hexを10進数として表示するため、結果は次のようになります。

16進数として読み取った値を10進数で表示すると: 10

つまり2回目は、

入力したA
↓
16進数として解釈
↓
16進数A
↓
10進数では10
↓
input_hexに10を格納
↓
10と表示

という流れです。

1回目と2回目を比較する

今回のプログラムで最も重要な部分を比較すると、次のようになります。

比較項目1回目2回目
入力AA
scanfscanf("%c", &input_char);scanf("%x", &input_hex);
変換指定%c%x
読み取り方1文字として読む16進数として読む
入力先の型charunsigned int
変数へ格納される意味文字A数値10
実行例での最終表示6510

特に注目したいのは、入力した文字はどちらもAであるという点です。

違っているのはscanfの変換指定です。

この違いによって、

Aを文字として読む

のか、

Aを16進数として読む

のかが決まります。

scanfを使用するときは、

何を入力するかだけでなく、scanfに何として読み取らせるのか

を意識することが大切です。

scanfのところでプログラムが止まるのは正常

scanfを初めて使ったとき、

「プログラムが途中で止まってしまった」

と思うことがあります。

たとえばプログラムを実行して、

文字を1つ入力してください(例:A)>

と表示されたまま画面が動かなくなったように見えることがあります。

しかし、これはエラーではありません。

scanfがユーザーからの入力を待っている状態です。

流れとしては次のようになります。

printfで入力案内を表示
        ↓
scanfを実行
        ↓
キーボード入力を待つ
        ↓
ユーザーが値を入力
        ↓
Enterを押す
        ↓
scanfが入力を読み取る
        ↓
次の処理へ進む

scanfがあるプログラムでは、実行しただけですべての処理が最後まで進むとは限りません。

ユーザーから必要な入力が行われるまで、その場所で待機します。

scanfで&を付け忘れない

scanfを使い始めたときに特に注意したいのが、&の付け忘れです。

たとえばint型のvalueへ入力するなら、基本的には次のように書きます。

int value;

scanf("%d", &value);

次のように&を書かない形は正しくありません。

scanf("%d", value);

scanfは読み取った値を変数へ書き込む必要があります。

そのため、valueの値そのものではなく、

&value

として、valueが置かれている場所を渡す必要があります。

初心者のうちは、

scanf
↓
変数へ値を書き込む
↓
書き込み先の場所が必要
↓
&変数名

と関連付けて覚えるとよいでしょう。

変換指定と変数の型を合わせる

scanfを正しく使用するためには、変換指定と入力先の変数の型を適切に対応させる必要があります。

今回登場した組み合わせなら、次のようになります。

読み取りたいデータ変換指定変数の型の例
10進整数%dint
1文字%cchar
16進整数%xunsigned int
浮動小数点数%lfdouble

たとえば、1文字を読み取る場合は次の組み合わせです。

char ch;

scanf("%c", &ch);

16進整数を読み取る場合は、次の組み合わせが基本です。

unsigned int number;

scanf("%x", &number);

変換指定だけ合っていても、入力先となる変数の型が合っていなければ、正しくデータを受け取れない原因になります。

scanfを書くときは、

変換指定と変数の型を1組として確認する

習慣を付けておくとよいでしょう。

%xの入力先にはunsigned intを使う

%xを使って16進整数を読み取る場合は、入力先としてunsigned int型の変数を使用します。

今回のプログラムでも次のように宣言しました。

unsigned int input_hex;

そしてscanfでは、

scanf("%x", &input_hex);

としています。

%xに対応する入力先はunsigned intへのポインタであるため、この組み合わせを基本として覚えておきましょう。

今の段階ではunsigned intの細かな仕組みまで覚える必要はありません。

まずは、

%xで入力する
↓
unsigned int型の変数を用意する
↓
scanf("%x", &変数名);

という組み合わせを押さえておけば大丈夫です。

printfとscanfをセットで考える

キーボード入力を行うプログラムでは、scanfだけを書くよりも、printfと組み合わせると分かりやすいプログラムになります。

基本的な流れは次の3段階です。

  1. printfで何を入力すればよいか表示する
  2. scanfで入力された値を受け取る
  3. printfで受け取った値を表示する

たとえば次のような形です。

printf("整数を入力してください > ");
scanf("%d", &value);
printf("入力した値は%dです\n", value);

最初のprintfがなければ、プログラムを実行したユーザーは、

「何を入力すればよいのだろう」

と迷ってしまいます。

scanfのあとにprintfで結果を表示すれば、入力した値がプログラムへ取り込まれたことも確認できます。

そのため、初心者のうちは、

入力案内
↓
入力
↓
結果確認

という流れでプログラムを書くと理解しやすくなります。

図3:printfとscanfを使った入力処理の基本パターン

この図から分かること

scanfを使った入力処理は、scanfだけを単独で考えるよりも、

printfで案内
↓
scanfで入力
↓
printfで結果確認

という一連の流れとして考えると分かりやすくなります。

最初のprintfはユーザーに何を入力するのか伝えます。

scanfは実際の入力を受け取り、指定された変数へ値を書き込みます。

最後のprintfでは、変数に格納された値を表示して確認できます。

この流れは、これからキーボード入力を使ったプログラムを作るときの基本的な形になります。

scanfを学び始めた段階で押さえておきたいこと

scanfを使った最初のプログラムでは、複雑な入力方法を一度に覚える必要はありません。

まずは次の点を意識してコードを確認してみましょう。

  • scanfはキーボードから入力されたデータを読み取れる
  • scanfを使うにはstdio.hをインクルードする
  • %dや%c、%xなどの変換指定で読み取り方が決まる
  • scanfへは基本的に&変数名の形で変数のアドレスを渡す
  • %cならchar、%xならunsigned intのように変換指定と変数の型を対応させる
  • scanfを実行すると、必要な入力が行われるまでプログラムは入力待ちになる
  • 同じAでも%cなら文字、%xなら16進数として解釈される
  • printfで入力案内を表示し、scanfで受け取り、printfで結果を確認すると流れを理解しやすい

特に重要なのは、scanfでは変換指定によって入力データの読み方が決まることです。

今回のAの例のように、

%c → Aという文字
%x → 16進数のA、つまり10

と、同じキーボード入力でも意味が変わります。

また、scanfは変数へ値を書き込む関数なので、

scanf("%d", &value);

のように、&を使って入力先となる変数の場所を渡す点も大切です。

まずは入力する → scanfが読み取る → 変数へ値が入る → printfで確認するという動きを自分で実行しながら確かめていくと、C言語のキーボード入力の仕組みがつかみやすくなります。