1

私はCで非常に単純なコマンドラインベースのプログラムを書いています。これはほんの小さなテストであり、コードは非常に単純です。つまり、ユーザーに名前、数学の成績、英語の成績、コンピューティングの成績を尋ねることを意味します。次に、彼らの平均成績を計算し、彼らが入力した名前も伝えます。はい、私はこれが非常に単純なプログラムであることを知っていますが、私はまだ何か間違ったことをしています。

問題は、コードの一部が最初に実行され、ユーザーに名前を入力するように指示します。次に、これを実行してEnterキーを押すと、残りのコードが一度に実行され、動作を停止します。何が悪いのかわからないのが変です。

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char chr;
    char firstname;
    int mathsmark, englishmark, computingmark, averagemark;

    printf("What is your name?\n");
    scanf("%c", &firstname);
    printf("\n");

    printf("What is your maths mark?\n");
    scanf("%d", &mathsmark);
    printf("\n");

    printf("What is your english mark?\n");
    scanf("%d", &englishmark);
    printf("\n");

    printf("What is your computing mark?\n");
    scanf("%d", &computingmark);
    printf("\n");

    printf("Your name is: %c", firstname);
    printf("\n");

    averagemark = (mathsmark + englishmark + computingmark) / 3;
    printf("%d", averagemark);
    printf("\n");

    chr = '\0';

    while (chr != '\n') {

        chr = getchar ();
    }

    return 0;
}
4

4 に答える 4

5

大きな問題の1つは、1文字の長さであると宣言firstnameし、コンソールから名前を読み取ろうとすると、%c変換指定子を使用していることです。変換指定子は、入力ストリームから次の1文字を読み取り、firstname。名前の残りの部分は、残りのscanf呼び出しを汚すために入力ストリームに残されます。

たとえば、名として「Jacob」と入力すると、最初のscanf呼び出しがに割り当てJられ、入力ストリームが firstname残ります。"acob\n"

次の呼び出しは整数値scanfに変換してに保存しようとしますが、失敗します(有効な整数文字列ではありません)。次の2回の呼び出し でも同じことが起こります。"acob\n"mathsmark"acob\n"scanf

最後のループ

while (chr != '\n')
{
   chr = getchar();
}

最後"acob\n"に、改行文字を含む残りの部分を消費し(名前を入力した後にEnterキーを押したため)、ループとプログラムを終了させます。

これをどのように修正しますか?

まず、:の配列firstnameとして宣言する必要があります。char

char firstname[SOME_SIZE] = {0};

ここで、SOME_SIZEすべてのケースを処理するのに十分な大きさです。scanf呼び出しを変更する必要があります

scanf("%s", firstname);

これはscanf、入力ストリームから次の空白文字までの文字を読み取り、その結果をfirstname配列に格納するように指示します。&ここでは演算子を使用する必要がないことに注意してください。ほとんどの場合、配列型のはポインタ型の式に変換(「減衰」)され、式の値は配列の最初の要素のアドレスになります。

scanfこれはあまり安全ではなく、あまり堅牢ではないことに注意してください。バッファのサイズよりも多くの文字を入力するとscanf、配列に続いてそれらの余分な文字がメモリに格納され、重要なものが壊れる可能性があります。次のように、変換指定子で明示的なフィールド幅を使用することで、これを防ぐことができます。

scanf(*%29s", firstname);

しかし、一般的にそれは苦痛です。

scanfまた、不正な入力の検出もあまり得意ではありません。マークの1つとして「12er」を入力すると、scanfが変換されて割り当てられ、次の読み取りをファウルするためにストリームに "12"残ります。"er"

scanf成功した割り当ての数を返すため、不正な入力を防ぐ1つの方法は、次のように戻り値を確認することです。

if (scanf("%d", &mathmarks) != 1)
{
  printf("Bad input detected for math marks\n");
}

残念ながら、scanfストリームから悪い文字を削除することはありません。自分でそれを行う必要がありますgetchar

于 2012-10-09T15:53:56.677 に答える
1

いくつかのチュートリアルを見たいと思うかもしれません。たぶん、1つはフォーマット指定子に、もう1つはCの文字列にあります

scanf()stdinフォーマット指定子から指定されたとおりにデータを読み取り、保存します。この場合:

char firstname;    
scanf("%c", &firstname); 

から1文字を読み取りstdin、保存しfirstnameます。

>> What is your first name?
Mike

今、私たちが要求したように1文字を読んだfirstname == 'M'ので。scanf()

あなたがしたかったのは文字列(文字の束)を読むことでした:

char firstname[5];        // an array of characters
scanf("%s", firstname);  // store as a string
firstname[4] = '\0';      // Truncate the result with a NULL to insure no overflow

>> What is your first name?
Mike

要求どおりに1つの文字列を読み取っfirstnameたため、[M] [i] [k] [e][\0]になりました。同じことが、にscanf()も当てはまることに注意してください。aを使用すると1文字になり、aを使用するとNULLターミネータまでのすべての文字が表示されます。printf()printf%cprintf()%s

于 2012-10-09T15:54:06.450 に答える
1

(少なくとも) 2 つの選択肢があります。

char firstname[number_big_enough_to_hold_long_name];
/*or */

char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);

さらに、読み取り幅を制限するのが最善です。scanf()のサイズ (使用可能なスペース) がわかりませんfirstname

scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */

char firstname[32];
if(scanf("%31s", firstname) == EOF) {
     perror("bad");
     return 1;
}

さらに、次の読み取りを試みる前に、何か残っているかどうかを確認する必要があります。つまり、誰かが「私の名前」firstnameを入力すると、「私の」だけが入力ストリームに残り、「名前」は入力ストリームに残ります。

そして、 not a char をgetchar()返します。int

于 2012-10-09T16:01:46.963 に答える
1

これは、新しい C/C++ 開発者の間でよくある間違いです。このscanf関数は、キーを押して入力の終わりを知らせることを検出しますが、入力文字列の最後にある文字ENTER/RETURNもキャッチするため、基本的に 2 つが検出されます。 and の使用例については、こちらを参照してください。\nRETURNS

fgetssscanf

http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html


この問題はすぐに解決されます。それまでの間、次の本を読むことを強くお勧めします。

http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965


北米の高校や大学で最も一般的に使用されている C プログラミングの本であり、実践に役立つ例がたくさんあります。上記で示したこの特定のプログラムを含めて。印刷版には電子ブックよりも多くの例があるので、印刷版の 30.00 ドルを払いたいと思います。

幸運を!

于 2012-10-09T15:48:06.493 に答える