第5章の2 scanf関数

1. scanf関数

キーボードから書式付きで入力します。
scanf() の f は “format”(書式) の f です。scanf() は printf() と同様に書式指定を行うことにより、「A」のキーを押しても、16進数で入力したり、文字で入力したりというように入力形式を変えることが出来ます。

【書き方】
scanf( 書式文字列, 格納可変個引数 );

(1) 書式文字列

“” で囲まれた文字列です。以下の変換指定だけを記述するのが一般的です。

【scanf の変換指定文字列】
変換指定文字列 意味 使われるデータ型
%c 1文字として入力する 文字型
%d 10進数で入力する 整数型
%x 16進数で入力する
%o 8進数で入力する
%f 浮動小数点数を入力する 浮動小数点型
%s 文字列を入力する 文字型配列
  • double型の入力は、変換指定子fの前に変換修飾子l(エル)を付加し、“%lf” と表記します。変換修飾子 l(エル)を忘れがちですので、注意してください。
  • long型の入力は、変換指定子の前に変換修飾子 l(エル)を付加し、“%ld” のように表記します。

(2) 格納可変個引数

入力データを格納する領域のアドレス(アドレスについてはポインタの章で詳しく説明します。)を指定します。

変数にキーボードからデータを入力

変数のアドレスを「&変数名」で記述します。

// 例
int dt;
scanf("%d", &dt);

文字型配列にキーボードから文字列を入力

配列の先頭要素のアドレスを「配列名」で記述します。「&」は不要です

// 例
char st[100];
scanf("%99s", st);    // 99文字以上は入力できない

配列要素数を超えて文字列を入力できないように入力フィールド幅を指定することが重要です。文字列の終端文字’\0’を考慮して、入力フィールド幅は「配列の要素数-1」に設定します。

scanf関数の使用例  サンプルプログラム

#include <stdio.h>

int main(void)
{
    char c;
    int i;
    float f;
    double d;
    long l;
    char st[80];

    printf("1文字入力=");
    scanf("%c",&c);                 // 文字読み込み '&'が必要
    printf("1文字出力:%c\n",c);

    printf("文字列入力=");
    scanf("%79s",st);               // 文字列読み込み '&'は不要
    printf("文字列出力:%s\n",st);

    printf("10進入力=");
    scanf("%d",&i);
    printf("10進出力:%d\n",i);
    
    printf("16進入力=");
    scanf("%x",&i);
    printf("16進出力:%x\n",i);

    printf("long入力=");
    scanf("%ld",&l);                // %ld でlong型入力を行う
    printf("long出力:%ld\n",l);
    
    printf("浮動小数点数入力=");
    scanf("%f",&f);
    printf("浮動小数点数出力:%f\n",f);

    printf("double入力=");
    scanf("%lf",&d);                // %lf でdouble型入力を行う
    printf("double出力:%16f\n",d);

    return 0;
}

【実行結果例】
1文字入力=a
1文字出力:a
文字列入力=abcde
文字列出力:abcde
10進入力=11
10進出力:11
16進入力=2b
16進出力:2b
long入力=1234567890
long出力:1234567890
浮動小数点数入力=12.345
浮動小数点数出力:12.345000
double入力=123456789.123456
double出力:123456789.123456

水色字はキーボードからの入力

2. scanf関数の注意事項

(1) 空白類(スペース、改行、タブなど)は読み込まない

scanf() の “%s” 変換では空白類がくると読み込みを終了します。そのため、

This is a pen.

といった文字列を読み込むことはできません。

この例では「This」だけが読み込まれます。 (空白類を含む文字列を読み込むときには fgets() を用います。fgets() については「標準入出力関数(2)」の章で説明します。)

(2) 改行文字が残る

キーボードから入力された文字はバッファと呼ばれる作業領域にいったん読み込まれ、エンターキーが入力されるとフラッシュ(バッファをクリアし、再びバッファリングが行える状態にすること)されます。

scanf() では、正しく入力しても最後の改行文字はバッファの中に残るため、おかしな動作になるときがあります。(scanf() 実行後に、scanf() の “%c” 変換を行ったとき)

【回避方法】
いくつか方法はありますが、一番簡単な回避方法は、

scanf(" %c", &c);

のように、%c の前に半角スペースを入れることです。このように記述すると、空白類文字を無視して次の文字を読み取ります。

(3) 読み込み不一致

変換指定文字列で、期待していなかったデータを入力すると、 バッファのデータをそのまま残し、動作を終了してしまいます。

// 例
int data;
scanf("%d", &data);    // 10進数値以外は入力しない

正しく入力できるように、printf() で入力ガイダンスを表示しましょう。
また、回避方法は「標準ライブラリ関数」の章で説明します。

〇 演習問題

問1

文字型配列 str[80] を宣言し、この str に好きな文字列をキーボードから入力しなさい。
入力したら、出力して内容を確認しなさい。

【実行結果例】
文字列の入力 = computer
入力文字列:computer

水色字はキーボードからの入力

問2

  1. キーボードから入力した10進数を、10進数と16進数で出力して内容を確認しなさい。
  2. キーボードから入力した16進数を、10進数と16進数で出力して内容を確認しなさい。
  3. キーボードから入力した1文字を、文字と10進数、16進数で出力して内容を確認しなさい。
  4. キーボードから入力した long型整数を、出力して内容を確認しなさい。
  5. キーボードから入力した float型浮動小数点数を、出力して内容を確認しなさい。
  6. キーボードから入力した double型浮動小数点数を、出力して内容を確認しなさい。

【実行結果例】
10進入力 = 11
10進出力:11
16進出力:b
16進入力 = 2b
10進出力:43
16進出力:2b
1文字入力 = A
1文字出力:A
10進出力:65
16進出力:41
long入力 = 1234567890
long出力:1234567890
float入力 = 12.345
float出力:12.345000
double入力 = 123456789.123456
double出力:123456789.123456

水色字はキーボードからの入力

解答例

// 問1
#include <stdio.h>

int main( void )
{
    char str[80];

    printf("文字列の入力 = ");
    scanf( "%79s", str );

    printf( "入力文字列:%s\n", str );

    return 0;
}
// 問2
#include <stdio.h>

int main( void )
{
    int a;
    printf("10進入力 = ");
    scanf("%d", &a);
    printf("10進出力:%d\n", a);
    printf("16進出力:%x\n", a);

    printf("16進入力 = ");
    scanf("%x", &a);
    printf("10進出力:%d\n", a);
    printf("16進出力:%x\n", a);

    char c;
    printf("1文字入力 = ");
    scanf(" %c", &c);
    printf("1文字出力:%c\n", c);
    printf("10進出力:%d\n", c);
    printf("16進出力:%x\n", c);

    long l;
    printf("long入力 = ");
    scanf("%ld", &l);
    printf("long出力:%ld\n", l);

    float f;
    printf("float入力 = ");
    scanf("%f", &f);
    printf("float出力:%f\n", f);

    double d;
    printf("double入力 = ");
    scanf("%lf", &d);
    printf("double出力:%f\n", d);

    return 0;
}

● 補足:Visual C++でscanfを使用する場合

Microsoft の Visual Studio で使われている C言語 および C++言語 のコンパイラである Visual C++ では、scanf などの一部の標準関数に対して、セキュリティ上の理由から警告やエラーが出ることがあります。特に scanf は、入力サイズの制限がない場合にバッファオーバーフローを引き起こしやすいため、Visual C++では、より安全な scanf_s関数 の使用が推奨されています。

Visual C++で標準の scanf を使いたい場合は、次の前処理指令を追加することで、セキュリティ警告を無効にできます。

#define _CRT_SECURE_NO_WARNINGS

この文をプログラム先頭に追加すると、scanf のようなセキュリティ警告を出す関数の使用を許可します。

標準の scanf はC言語の基本的な関数として、多くの開発環境で広く使われていますが、バッファオーバーフローの危険性があるのも事実です。そこで、scanf(“%99s”, str); のように、必ず入力フィールド幅を指定して、入力の安全性を確保するようにしましょう。

コメント