Search code examples
cloopsfrequencyinfiniteletter

Infinite loop when trying to count letter frequencies


#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;
}

So I have a program that counts the frequencies of letters that appear in standard input until EOF. But once I reach EOF, my program just goes into an infinite loop and the frequencies doesn't seem to be right. When I just put a print statement to enter a single string, it works fine. I don't really know what the problem is. Would anybody be able to help me with this?


Solution

  • if (a == EOF) should be right after a = scanf("%s", string);

    Then that if() condition should exist the loop.

    Should reset c = 0 each time in loop

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

    With the above changes, confident your code will run fine. There are other things to consider on lesser degree. 1) The scanf("%s",... is unbounded. 2) Should limit input. if (a == EOF) might as well code after the loop. 3) Suggest the loop condition is the positive affirmation that scanf()==1. Loop on what is good, not exit on a case of what is bad. 4) Consider unsigned vs. int for counting. 5) A for() loop rather than while() is nice for incremental loops. 6) Avoid magic numbers like 26.

    BTW: Your code had nice use of casting for floating point, A literals and array {0} initialization.

    #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;
    }