0

I have this function that reads text from a user and counts how many letters of each type there are. However, the function doesn't wait for the user input when called.

What I'd typically try is to put a space before the %c however adding this space makes it so the program doesn't proceed after you hit enter.

 void ReadText(int histo[], int *max) {

    int i;
     char userInput;

    printf("ENTER A LINE OF TEXT:\n");
    do{

    if (scanf("%c", &userInput) != 1)
    break;

  if(userInput >= 97 && userInput <= 122)
     histo[userInput-97] = histo[userInput-97] + 1;
  else if(userInput >= 65 && userInput <= 90)
     histo[userInput-65] = histo[userInput-65] + 1;

  }while(userInput != '\n');

  for(i = 0; i < 26; i++)
  printf("%d ", histo[i]);

    *max = histo[0];

   for(i = 0; i < 25; i++)
      if(histo[i] > *max)
         *max = histo[i];
}





int main() {   

   char command;
   int i, max;
   int histo[26] = {0};

   //User Input Validation

   do{

   printf("Enter command (C, R, P, or Q): ");
   scanf(" %c", &command);

   switch(command) {

  case 'C': case 'c':
     for(i = 0; i < 25; i++)
        histo[i] = 0;
     break;            

  case 'R': case 'r':    
     ReadText(histo, &max);
     break;

  case 'P': case 'p':      
     DrawHist(histo, max);
     break;

  case 'Q': case 'q':
     return 0;

  default:

     printf("Invalid Command %c", command);
     printf("\n");      
  }
   }while(1);

   return 0;
}
  • Why do you think it doesn't work? Adding a `main` function that just calls this works fine... – Chris Dodd Apr 16 '19 at 05:47
  • `What I'd typically try`...where? – Sourav Ghosh Apr 16 '19 at 05:55
  • A space character in the format string causes `scanf()` to read and discard whitespace. That will happen if you hit a letter followed by newline, so the newline character will be discarded - and the while loop will never end. – Peter Apr 16 '19 at 05:55
  • @ChrisDodd I attached my main too, it doesn't work for me...?!?!? – Bill Karver Apr 16 '19 at 05:59
  • @Peter So what would the fix be? If I have no space it doesnt wait for the user – Bill Karver Apr 16 '19 at 06:00
  • The fix is to not use `scanf()` if you care about handling whitespace, as you apparently do. Use `fgets()` to read an entire line (up to and including the newline) at once. Then interpret the line read. Bear in mind that if the buffer supplied to `fgets()` is shorter than a line of input, that `fgets()` will read the line in pieces. – Peter Apr 16 '19 at 06:17
  • @Peter Sorry If I confused you I'm not looking to handle whitespace. – Bill Karver Apr 16 '19 at 06:23
  • If you are fiddling with `scanf()` format to get it to behave differently depending on whether there is whitespace (space characters, newlines, etc) or not in the input, then you are handling whitespace. – Peter Apr 16 '19 at 06:33
  • @Peter I do not want to handle whitespace as I just said, I mentioned that in the past putting a space has fixed my issue, but its not a fix this time. – Bill Karver Apr 16 '19 at 06:39

3 Answers3

1

When I first wrote this answer, the main() program was not provided. Now that it is provided, the primary problem is that scanf() leaves the newline in the input buffer. When the main program reads the r (or R), the newline after it is left in the buffer. The code in ReadText() immediately reads that newline, and nothing more.

Adding the space in " %c" in ReadText() means that all blanks, tabs and newlines will be read while processing the space, and only when something that isn't white space is entered will the input terminate. For your code here, using just "%c" is correct and necessary (unless you decide to use getchar() instead). You should handle EOF too; in ReadText(), you should check:

if (scanf("%c", &userInput) != 1)
    break;

The best fix is probably to use a function like:

static void gobble(void)
{
    int c;
    while ((c = getchar()) != EOF && c != '\n')
        ;
}

and call it in main() after the scanf() to read the command character:

printf("Enter command (C, R, P, or Q): "); if (scanf(" %c", &command) != 1) return 0; // EOF most probably gobble();

The " %c" here (in main()) is sensible. It is not appropriate in ReadText().

Remember: scanf() is probably the hardest function to use really well in standard C — it is excruciatingly complex and subtle, and any given call is often affected by prior input operations, especially previous calls to scanf(). Recovery after an error in the input is also rather hard unless you use a function like gobble() to clean out any left over unread residue on the line — but the diagnosis of what went wrong is hard too. It is often better to read the line with fgets() (or POSIX getline()) and then scan it with sscanf(), which allows you to (a) make multiple attempts at parsing the same data, and (b) allows you to report the entire faulty line rather than just what fragments are left after scanf() has read some but not all of the line.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I added this in, but that doesn't fix the issue I'm running into. – Bill Karver Apr 16 '19 at 06:02
  • The `if (scanf(…) != 1)` was intended to replace the existing, unchecked `scanf(…)`. – Jonathan Leffler Apr 16 '19 at 06:03
  • Also, the behaviour depends on what's gone before. If you did some input before you called this function, then you could be running into the "`scanf()` leaves the newline in the input buffer" problem head on — the first character read is in fact a newline from after some previous input. – Jonathan Leffler Apr 16 '19 at 06:04
  • In order to call this function you need to type r or R and then enter so what your saying is this is causing my issue. How would this get fixed? Sorry Im being a pain, It's late here and I should probably wait till morning, but I'd prefer to get this done now – Bill Karver Apr 16 '19 at 06:08
  • Probably best to call a function to eat up to the newline after the previous input operation — a function like `static void gobble(void) { int c; while ((c = getchar()) != EOF && c != '\n') ; }` or thereabouts to eat up to the next newline (or EOF). – Jonathan Leffler Apr 16 '19 at 06:15
1

The problem is in your main function -- you call scanf(" %c" to read the command, which leaves the newline after that in the input buffer. So when you call ReadText, the first thing it reads is that newline, and it returns immediately.

You need to add some code to read (and discard) the rest of the current input line before calling ReadText.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

In main added works like a charm, thanks for the talking people!

  case 'R': case 'r':   
     while((c = getchar()) != '\n' && c != EOF); //Clear the newlines
     ReadText(histo, &max);
     break;