2016-05-15 4 views
1

私はユーザーがムービーを入力し、ユーザーが入力した情報をプリントアウトできるプログラムを構築しています。fscanfで入力を取得する

私はstructを使って映画の変数を定義しています。問題は、ユーザが最初にfscanf()と入力し、スペースがである場合です。例:「マイアミバイス」他のすべてがお互いの後に印刷されます。 stdinは動作しません。そして、なぜこれが起こっているのかわかりません。

私はgets()について読んできましたが、セキュリティ上の問題がありましたので、代わりにfgets()またはfscanf()を使用する必要があります。しかし、私はここで何が問題なのか理解できません。

main.cの

struct movie { 
    char title[40]; 
    int rate; 
    int year; 
}; 
+0

'関数fscanf(STDIN、 "%sの"、m.title);' - - > 'fscanf(stdin、"%39 [^ \ n]%* c "、m.title); ' – BLUEPIXY

+1

@BLUEPIXYさて、なぜですか?それは私には奇妙に見えるので、私はそれが実際に何を理解する必要があります。コメントをいただきありがとうございます。 –

+0

'%s'にはスペースが含まれていません。 '%[^ \ n]'は改行文字以外は読み込みます。 – BLUEPIXY

答えて

0

%s形式は、単一のワードを読み取るためにscanfに指示

#include <stdio.h> 
#include <stdlib.h> 
#include "main.h" 

int main() 
{ 
    struct movie m; 

    puts("What was the title of the movie you saw?"); 
    fscanf(stdin, "%s", m.title); 
    puts("What was the relase year?"); 
    fscanf(stdin, "%d", &m.year); 
    puts("How would you rate the movie? (1-10)"); 
    fscanf(stdin, "%d", &m.rate); 

    printf("You saw the movie %s which was released %d and you rated it a %d", m.title, m.year, m.rate); 

    return 0; 
} 

main.h。空白は単語セパレータとして機能し、したがって、は、m.titleに、Viceは、入力ストリームにとどまります。その後のscanf%d形式の呼び出しでは、ストリームから整数を解析できず、0を返し、m.yearm.dateは未初期化とします。したがって、最後にprintfを呼び出して値を出力するとき、未定義の動作を呼び出します。

異なる形式で問題を修正することができます:。さらに、がm.titleの末尾を超えて、幅指定子:%39[^\n]を書き込まないようにする必要があります。フォーマットの前に追加のがあると、ムービータイトルの前に空白があればそれをスキップします。追加の%*c\nとなりますが、それ以降のscanf("%d",...)は、入力ストリームに保留されている\nを含む先頭の空白をスキップします。

#include <stdio.h> 
#include <stdlib.h> 

struct movie { 
    char title[40]; 
    int rate; 
    int year; 
}; 

int main(void) { 
    struct movie m; 

    puts("What was the title of the movie you saw?"); 
    if (scanf(" %39[^\n]", m.title) != 1) 
     return 1; 
    puts("What was the release year?"); 
    if (scanf("%d", &m.year) != 1) 
     return 1; 
    puts("How would you rate the movie? (1-10)"); 
    if (scanf("%d", &m.rate) != 1) 
     return 1; 

    printf("You saw the movie %s which was released in %d and you rated it a %d\n", 
      m.title, m.year, m.rate); 

    return 0; 
} 
+0

「あなたは、幅指定子を持つm.titleの終わりを超えて**書き込み**から 'scanf'を防ぐべきですか? – user3078414

+0

@ user3078414:フォーマット '%39 [^ \ n]"は、 'stdin'から' m 'にコピーされる最大 '39'文字を指定します。したがって、 'scanf'が' 40'バイト配列の終りを越えて書き込みを行うことを効果的に防ぎます。そうすることをお勧めします。 '*'はターゲット配列の幅を指定することはできませんが、 'scanf_s'はこの欠点を修正しますが、エラー処理の意味は複雑すぎるので、この関数は常に利用できるとは限りません。 – chqrlie

+0

これは私が理解するものです。私はこの文脈で、そして "scanf"に関連して "書く"という言葉に遭遇したことはありません。 – user3078414

1

を入力としてfgets()読んたび文字列を使用してみてください:ここで

は、あなたのプログラムの修正版です。とにかくここに私が少し修正したコードがあります。自分のニーズに合わせてコードを変更してください。

#include<stdio.h> 
#include<string.h> 
#include<stdlib.h> 

struct movie { 
    char title[40]; 
    int rate; 
    int year; 
}; 

int main(){ 

    struct movie m; 
    char *newline_char=NULL; 

    puts("What was the title of the movie you saw?"); 
    fgets(m.title,40,stdin); 

    //The below two lines of code are used to remove the '\n' 
    //character from the input since fgets() also stores the '\n' 
    //character. Replace the '\n' char with '\0' character. 
    if((newline_char=strchr(m.title,'\n')) != NULL){ 
    *newline_char = '\0'; 
    } 

    puts("What was the relase year?"); 
    fscanf(stdin, "%d", &m.year); 
    puts("How would you rate the movie? (1-10)"); 
    fscanf(stdin, "%d", &m.rate); 

    printf("You saw the movie %s which was released %d and you rated it a %d", m.title, m.year, m.rate); 
    return 0; 
} 

chuxが推奨するように、またのみfgets()を使用することができ、コードで以下に示すようにfscanf()を避けるため、

#include<stdio.h> 
#include<string.h> 
#include<stdlib.h> 

struct movie { 
    char title[40]; 
    int rate; 
    int year; 
}; 

int main(){ 

    struct movie m; 
    char *newline_char=NULL; 
    char input[256]; 

    puts("What was the title of the movie you saw?"); 
    fgets(m.title,40,stdin); 

    if((newline_char=strchr(m.title,'\n')) != NULL){ 
     *newline_char = '\0'; 
    } 

    puts("What was the relase year?"); 
    fgets(input,256,stdin); 
    sscanf(input,"%d",&m.year); 
    puts("How would you rate the movie? (1-10)"); 
    fgets(input,256,stdin); 
    sscanf(input,"%d",&m.rate); 

    printf("You saw the movie %s which was released %d and you rated it a %d", m.title, m.year, m.rate); 
    return 0; 
} 
+1

'fgets()'を使うのが最善の方法です。それでも 'fgets()'と 'fscanf(stdin、...)を混在させると、コードループに問題が発生します。' fgets() 'のみを使用することをお勧めします。 – chux

関連する問題