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

int main(void)
{
    char string[100];
    int c = 0, count[26] = {0};
    int accum = 0;
    int a;

    while(1)
    {
       a = scanf("%s", string);
       while ( string[c] != '\0' )
       {

           if ( string[c] >= 'a' && string[c] <= 'z' ){
            count[string[c]-'a']++;
            accum++;
           }

           else if (string[c] >= 'A' && string[c] <= 'Z'){
            count[string[c]-'A']++;
            accum++;
           }
            c++;
       }
       if (a == EOF)
       {
           for ( c = 0 ; c < 26 ; c++ )
           {
            if( count[c] != 0 )
                printf( "%c %f\n", c+'a', ((double)count[c])/accum);
           }
       }
    }
   return 0;
}

そのため、EOF まで標準入力に現れる文字の頻度をカウントするプログラムがあります。しかし、EOF に達すると、プログラムが無限ループに入り、周波数が正しくないように見えます。単一の文字列を入力するためにprintステートメントを配置するだけで、正常に機能します。何が問題なのかよくわかりません。誰でもこれで私を助けることができますか?

4

3 に答える 3

2

if (a == EOF)直後にすべきa = scanf("%s", string);

次に、そのif()条件がループに存在する必要があります。

c = 0ループのたびにリセットする必要があります

while(1) {
   a = scanf("%s", string);
   if (a == EOF) {
     ...
     break;
   }
   c = 0;
   while ( string[c] != '\0' ) {

上記の変更により、コードが正常に動作することを確信できます。程度が低い場合は、他にも考慮すべきことがあります。1)scanf("%s",...は無制限です。2) 入力を制限する必要があります。 if (a == EOF)ループの後にコーディングすることもできます。3) ループ条件は、肯定的な肯定であることを示唆しますscanf()==1。何が悪いかのケースで終了するのではなく、何が良いかをループします。unsigned4)対数を考えるint。5)インクリメンタル ループにはfor()むしろループの方が適しています。while()6) 26 のようなマジック ナンバーを避ける。

ところで:あなたのコードは、浮動小数点、Aリテラル、および配列の{0}初期化にキャストをうまく使用していました。

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

int main(void) {
  char string[100];
  unsigned count['z' - 'a' + 1] = { 0 };
  unsigned accum = 0;

  while (scanf("%99s", string) == 1) {
    for (int c = 0; string[c]; c++) {
      if (string[c] >= 'a' && string[c] <= 'z') {
        count[string[c] - 'a']++;
        accum++;
      } else if (string[c] >= 'A' && string[c] <= 'Z') {
        count[string[c] - 'A']++;
        accum++;
      }
    }
  }
  for (int c = 'a'; c <= 'z'; c++) {
    if (count[c - 'a'] != 0)
      printf("%c %f\n", c, ((double) count[c - 'a']) / accum);
  }
  return 0;
}
于 2014-11-01T23:10:51.060 に答える
0

無限ループは、次の行によって発生します。

while(1)

不要な場合は削除するか、breakどこかにステートメントを追加してください。

于 2014-11-01T23:10:23.160 に答える
0

あなたの問題と解決策を説明するのに役立ついくつかの言葉があります(chuxによって提案されています)。

while(1)最初の問題は、ループを終了するロジックがないことです。

IE は、コード化したものであるため、無限ループがあります。

EOF を検出しても、それについては何もしません。「EOF が発生したので、このwhile(1)ループを終了する必要があります」というコードは何もありません。

これは、chux が彼の答えで示唆していることbreakです。それがステートメントの目的です。「今すぐループから抜け出す」と言っています。

EOF があるかどうかを確認する前に、文字列を解析しているという追加の問題もあります。aがの場合EOF、文字列を取得していないため、文字列を解析してはなりません。

したがって、EOFチェックが文字列解析の前に行われるようにコードを再配置する必要があり、検出後に文字列の出力が終了しEOFたら、break.

于 2014-11-02T00:15:41.373 に答える