Thread: While loop not stopping for scanf for some reason. please help!

  1. #1
    Registered User
    Join Date
    Oct 2011
    Posts
    24

    While loop not stopping for scanf for some reason. please help!

    Ok I have a while loop here which contains a switch statement (I have only fleshed out case 1) and functions normally , except for when in case 1 I hit CTRL-D (for EOF, could be CTRL-Z for you). This sends it into an infinite loop and ignores the scanf at the top of the while loop, which it would usually stop at. I do not understand why. Does anyone know?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    
    
    #define MAXLINES 5
    
    
    int main (void)
    {
        int counter=1;
        float data[MAXLINES];
        int array_index=0;
        int x;
        int menu_selection = 1;
        int program_continue = 1;
        
        
        
        
        while (program_continue == 1)
        {
            
            printf("This program will perform the following: 1,2,3\n");
            printf("select 1,2,3\n");
            scanf("%d",&menu_selection);
            
            x=1;
            
            switch (menu_selection)
            {
                case 1:
                    while ( (array_index <= MAXLINES-1) )
                    {
                        printf("enter data line #%d:",counter);
                        scanf("%f",&data[array_index]);
                        array_index++;
                        counter++;
                        
                        if ( ( x=getchar() ) == EOF)
                            array_index = MAXLINES+1;
                    }
                    
                    if (counter > MAXLINES)
                        printf("\n\nNumber of data lines: %d\n",counter-1);
                    
                    if (counter < MAXLINES)
                        printf("\n\nNumber of data lines: %d\n",counter-2);
                    
                    array_index = 0;
                    
                    break;
                    
                case 2:
                    printf("continuing\n\n");
                    break;
                    
                case 3:
                    printf("goodbye!");
                    program_continue = 0;
                    break;
                    
                default: printf("That is not a valid entry.\n");
            }
            
        }
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Nov 2011
    Location
    Saratoga, California, USA
    Posts
    334
    In order to end the loop (program_continue == 1) must be false and you only do that for case 3.

  3. #3
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    I understand that. The while loop is basically the whole program and Case 3 is for when the user wants to exit the program. The problem I'm having is that when user selects 1 (case 1) and then exits with EOF (if( ( x=getchar() ) == EOF)array_index = MAXLINES+1 It goes into and infinite loop where it prints this:

    "This program will perform the following: 1,2,3select 1,2,3
    enter data line #5:


    Number of data lines: 5"


    over and over again forever until you force quit the program. For some reason it stops registering the scanf at the top of the while loop.

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Have you received any advice on adding getchar()'s in loops with scanf()'s lately, Charlie?


  5. #5
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    Nope!

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    If you use scanf(), it will always leave a newline char behind, in the input stream.

    Scanf() can ignore it, if the input is the wrong size, but sometimes it will goof up, and accept the newline, as your entry. Especially if the scanf() is for a type char - then it will always seem to "skip" the entry, and go on.

    Likewise, if you are requesting an integer, and the user enters a letter, the loop will crash your program:

    Code:
    #include <stdio.h>
    
    int main(void) {
    
      int i=1;
    
      while(i != 0) {
        printf("Enter a number [0 to quit], or a letter and watch out!"); 
        scanf("%d", &i);
      }
      return 0;
    }
    If you enter a letter (just one), the program will crash. Add a getchar() after the scanf(), and suddenly, it's fine again, although you enter a letter.

    You can add a space before the 'd' in the format for scanf(), and that will do about the same thing.

    If the user enters several letters, the getchar() will remove only one char, per loop, but the program will not crash.

    You'll learn more advanced ways to guard against bad user input, later on, and I'm not sure this is your problem with your program, but this is THE most common error in C, I believe. (maybe = and == confusion are as common though)

    So when I see scanf()'s used in a loop, without such guards in place, and the program is looping until it crashes - it's the first thing that crosses my mind.

    Give it a try.

  7. #7
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    Well I tried putting in an extra getchar() and putting a space in front of the %d and the %f. Neither of those seemed to work...

  8. #8
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Charlie Lesoine View Post
    Well I tried putting in an extra getchar() and putting a space in front of the %d and the %f. Neither of those seemed to work...
    Show us the code where you did this... please.

  9. #9
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    Ok well first I tried just with the spaces before the %d and %f on line 27 and line 37:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    
    
    #define MAXLINES 5
    
    
    int main (void)
    {
        int counter=1;
        float data[MAXLINES];
        int array_index=0;
        int x;
        int menu_selection = 1;
        int program_continue = 1;
        
        
        
        
        while (program_continue == 1)
        {
            printf("This program will perform the following: 1,2,3\n");
            printf("select 1,2,3\n");
            scanf(" %d",&menu_selection);
            
            switch (menu_selection)
            {
                case 1:
                    while ( (array_index <= MAXLINES-1) )
                    {
                        printf("enter data line #%d:",counter);
                        scanf(" %f",&data[array_index]);
                        array_index++;
                        counter++;
                        
                        if ( ( x=getchar() ) == EOF)
                        {
                            array_index = MAXLINES+1;
                        }
                    }
                    if (counter > MAXLINES)
                        printf("\n\nNumber of data lines: %d\n",counter-1);
                    
                    if (counter < MAXLINES)
                        printf("\n\nNumber of data lines: %d\n",counter-2);
                    
                    array_index = 0;
                    
                    break;
                    
                case 2:
                    printf("continuing\n\n");
                    break;
                    
                case 3:
                    printf("goodbye!");
                    program_continue = 0;
                    break;
                    
                default: printf("That is not a valid entry.\n");
            }
            
        }
        return 0;
    }

    That did not work. Then I tried putting a getchar(); on line 38, that did not work. Then I tried putting it on line 44 after it exits the while loop inside case 1. That did not work. Then I tried putting it on line 28, that also did not work.
    Last edited by Charlie Lesoine; 11-24-2011 at 03:08 PM.

  10. #10
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Ok, thanks... The problem with scanf() is that when the conversion fails it will not consume the content of the input buffer...

    For example...
    Code:
    int input = 0;
    
    do 
      { printf("Enter your id number : ");
         scanf("%d", &input); }
    while (input < 1);
    ... will go into an infinite loop if you type the letter A and hit enter.

    Frankly I see this as a terrible flaw in C's input functions, they should ALWAYS wait, no matter what... others will have varying opinions.

    There are several strategies for fixing the problem...

    The best one seems to be to treat all input as strings then sscanf() the values out after it's in the buffer since this method completely consumes the input buffer each time...
    Code:
    int input = 0;
    char buffer[100];
    do 
      { printf(" Enter your ID Number : ");
         fgets(buffer, 99, stdin);
         sscanf(buffer, "%d", &input; }
    while (input < 1);
    This method, which is a bit simpler to implement, discards the buffer after the fact...
    Code:
    int input = 0;
    
    do
      { printf("Enter your ID Code :");    
        scanf("%d", &input);
        while(getchar() != '\n'); }
    while (input < 1);
    There are many other ways of cleaning up C's flawed data entry routines and you should look for and experiment with them until you find one to your liking. It's probably best to take the code fragment you like best and make it into a function ... int GetInput(void) ;... to do the work for you in a re-useable manner.
    Last edited by CommonTater; 11-24-2011 at 03:32 PM.

  11. #11
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    Thanks Tater! I used the second option you provided. Worked like a charm!

  12. #12
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Charlie Lesoine View Post
    Thanks Tater! I used the second option you provided. Worked like a charm!
    You're welcome...

  13. #13
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    Now the program is hanging after returning to the main while loop. It is not getting stuck in an infinite loop, but it still does not respond to the scanf. For example, user first selects option 1 and enters a 3 or 4 data lines and then hits EOF (ctrl-z or ctrl-d), then it returns to the main while loop and prints

    "This program will perform the following: 1,2,3
    select 1,2,3"

    but then after that it hangs, will not respond to the scanf:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    
    
    #define MAXLINES 10
    
    
    int main (void)
    {
        int counter, printer_counter=1;
        float data[MAXLINES];
        int array_index=0;
        int x;
        int menu_selection = 0;
        int program_continue = 1;
    
    
        while (program_continue == 1)
        {
            printf("This program will perform the following: 1,2,3\n");
            printf("select 1,2,3\n");
    
    
            scanf(" %d",&menu_selection);
            while(getchar() != '\n');
            
            switch (menu_selection)
            {
                case 1:
                    counter=1;
                    
                    while ( (array_index <= MAXLINES-1) )
                    {
                        printf("enter data line #%d:",counter);
                        scanf(" %f",&data[array_index]);
                        array_index++;
                        counter++;
                        
                        if ( ( x=getchar() ) == EOF)
                        {
                            array_index = MAXLINES+1;
                        }
                    }
                    if (counter > MAXLINES)
                        printf("\n\nNumber of data lines: %d\n\n\n",counter-1);
                    
                    if (counter < MAXLINES)
                        printf("\n\nNumber of data lines: %d\n\n\n",counter-2);
                    
                    array_index = 0;
                    
                    break;
                    
                case 2:
                    printf("CASE 2 testing\n\n");
                    while ( (array_index < MAXLINES) || printer_counter < counter)
                    {
                        printf("data line #%d:",printer_counter);
                        printf("%f\n",data[array_index]);
                        array_index++;
                        printer_counter++;
                    }
                    array_index = 0;
                    printer_counter = 1;
                    printf("\n");
                    break;
                    
                case 3:
                    printf("goodbye!");
                    program_continue = 0;
                    break;
                    
                default: printf("That is not a valid entry.\n");
            }
            
        }
        return 0;
    }
    Any suggestions?

  14. #14
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Charlie Lesoine View Post
    Any suggestions?
    A few...
    1) Your operator prompting needs serious improvement. Look at your program from the position of someone who's been plunked down in a chair and told "do this"... You need to give concise instructions at each input. (Hint: Half of error avoidance is telling the operator what's needed.)

    2) You did not fully implement the data entry solutions I gave you... You really do need the scanf() and getchar() in a loop so that the program cannot proceed without valid data... Starting at line 22 to line 28...
    Code:
    printf("Please select :  1) Data Entry,  2) View Data,  3) Exit\n");
    do 
      { 
         printf(" Your choice  (1, 2 or 3) : "); 
         scanf(" %d",&menu_selection);
         while(getchar() != '\n');
      }
    while (menu_selection < 1 || menu_selection > 3);

    3) You should not use CTRL-D or CTRL-Z to break out of loops... First because most operators won't have the first clue what you're talking about and secondly because, as you're finding out, it's a real nuisance to work with. Plus it can be different on different OSs and even different versions of the same OS... Usually the exit is an impossible value. For example if you are getting 20 positive numbers from the operator, break the loop on any negative number or if your acceptable input range is -999 to +2000 break the loop on any value outside that range.

    4) It is generally unwise (but technically not wrong) to put a lot of code in a switch() statement. When the day comes you have a 10 page long switch statement and a brace goes missing, trust me, you will know what hell looks like. The far smarter strategy is to compartmentalize each case in a function and use the switch() to call the functions... Like this...
    Code:
    switch (UserInput())
      {
         case 1 :
            DataEntry(array,MAXLINES);
            break;
         case 2 :    
            DataDisplay(array,MAXLINES);
            break;
         // and so on
         default :
            HandleInvalidEntry();
      }
    In this way your code becomes highly modular, each function can be modified, rewritten or outright replaced without messing up the rest of the program.
    Last edited by CommonTater; 11-25-2011 at 12:03 PM.

  15. #15
    Registered User
    Join Date
    Oct 2011
    Posts
    24
    Yeah I didn't put in the operator prompt fully yet, I was just trying to figure out the code first.

    Also, using EOF is part of the assignment for my class. It is from the book C by Discovery which is my textbook.

    Didn't see the need to create functions, since each function would only be called once. Yes I know functions are key to making well organized code.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. get input wihout stopping loop
    By linux_kid in forum Linux Programming
    Replies: 2
    Last Post: 01-06-2011, 05:12 AM
  2. beginner question about stopping a for-loop.
    By Techboy10 in forum C Programming
    Replies: 3
    Last Post: 12-11-2008, 05:15 PM
  3. Stopping a Loop
    By Catman188 in forum C Programming
    Replies: 2
    Last Post: 02-14-2008, 10:14 PM
  4. Replies: 13
    Last Post: 12-10-2007, 07:53 AM
  5. Stopping an Infinite Loop
    By linuxpyro in forum C Programming
    Replies: 4
    Last Post: 11-30-2006, 12:21 PM

Tags for this Thread