scanfよりもfgets&sscanf(or sscanf_s)を使うこと

C言語ポインタ完全制覇 2-1

書き忘れ。


scanfを使うと、マッチしなかったデータが入力ストリームの残ってしまうので次のscanf等の呼び出しでおかしくなってしまう可能性がある。

それをさせないためにまずfgetsで改行までの入力を先に全て取得し、改めてsscanfで取り出した方が安全である。

#include <stdio.h>

int main (void) {
    int num;
    char str[256];
    
    scanf("%d",&num);
    scanf("%s",str);
    
    printf("%d - %s",num,str);
    
    return 0;
}
$ main
123ab
123 - ab

「123ab」を入力すると、二つ目のscanfで待ち状態にならずに一気に入力が終わってしまいます。

これは一つ目のscanfが123だけを解釈し、二つ目のscanfが入力ストリームまだ残っているabを取得してしまうからです。

この挙動はエラー処理や入力チェック等がやりにくくなる上に、常に入力ストリームに何が残っているかを意識しないといけなくなるので非常に面倒です。

#include <stdio.h>

int main (void) {
    int num;
    char buf[256];
    char str[256];
    
    fgets(buf,sizeof(buf),stdin);
    sscanf(buf,"%d",&num);
    
    fgets(buf,sizeof(buf),stdin);
    sscanf(buf,"%s",str);
    
    printf("%d - %s",num,str);
    
    return 0;
}
$ main
123ab
abcd
123 - abcd

このようにfgetsで一行分先に取得してからsscanfで値を取得すれば、必要のないデータを除外できます。また全てのデータはbufに格納されているため、入力ストリームに残っている値を気にする必要はありません。なのでbufだけを対象にエラー処理することができます。

ちなみにsscanfだとVC2008で警告が出るのでsscanf_sを使うべきでしょう。

#include <stdio.h>

int main (void) {
    int num;
    char buf[256];
    char str[256];
    
    fgets(buf,sizeof(buf),stdin);
    sscanf_s(buf,"%d",&num,sizeof(int));
    
    fgets(buf,sizeof(buf),stdin);
    sscanf_s(buf,"%s",str,sizeof(str));
    
    printf("%d - %s",num,str);
    
    return 0;
}