1

教授から渡された C コードの一部を理解するのに少し苦労しています。コードは次のとおりです。

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

int main()
{
  char name[1000];

  printf( "What's your name? " );
  scanf( "%s", name );
  printf( "name is %s\n", name );

  scanf( "%[^\n]", name ); /* read the entire line (up to but not
                              including the '\n' at then end) */

  getchar(); /* consume the newline from the input */

  printf( "name is %s\n", name );

  return EXIT_SUCCESS;
}

ユーザーは名前を入力し、次のように 2 回出力します。

What's your name? Dan
name is Dan
name is Dan

これがどのように機能するかは私を混乱させます。プロンプトは printf で出力され、入力は scanf でバッファに読み込まれ、バッファは printf で出力されます。ただし、2 番目の printf の \n はバッファをクリアする必要があるため、2 番目の scanf の読み取りはどこから行われるのでしょうか? ユーザー入力を待つと思いますが(空のバッファーがあれば)、そうではなく、単に名前を知っているだけです。これはどのように作動しますか?

4

1 に答える 1

4

2 番目のscanf()呼び出しはジャムし、何もしませんでした。これは、次に読み取る文字が\n. scanf()「空の」入力を処理せず、nameバッファを変更せずにそのままにします。nameは変更されていないため、2 番目のprintf()名前は最初の名前と同じprintf()です。

の戻り値を確認するscanf()と、2 番目の値が を返したことに気付くでしょう0。これは、入力をスキャンしなかったことを意味します。

このコードの使用方法には危険がありますscanf()。入力指定子は読み取るバイト数を通知しないため、入力がバッファscanf()をオーバーランする可能性があります。nameこれにより、未定義の動作が発生する可能性があり、最悪の場合、スタック スマッシュ攻撃に使用される可能性があります。scanf()スキャンするバイト数が多すぎないように通知することで、この問題を防ぐことができます。

    scanf( "%999s", name );

    scanf( "%999[^\n]", name );

長さは、 のフォーマット文字列で綴る必要がscanf()あります。可変引数内の引数としてこの情報を提供する方法はありません。通常fgets()、ユーザー入力を処理するために使用してから、それsscanf()を解析するために使用する方が信頼性が高いと考えられています。

    /* get the name */
    char input[sizeof(name)];
    input[sizeof(input)-2] = '\n'
    if ( fgets( input, sizeof(input), stdin ) != 0 ) {
        if ( sscanf( "%s", name ) == 0 ) name[0] = '\0';
    }

    /* get the rest of the line in case it was really long */
    while ( input[sizeof(input)-2] && input[sizeof(input)-2] != '\n' ) {
        input[sizeof(input)-2] = '\n';
        if ( fgets( input, sizeof(input), stdin ) == 0 ) break;
    }
于 2013-10-10T19:08:46.353 に答える