-1

I am implementing a Stack data structure using an array. To perform an operation on a stack like Push or Pop or Exit from Program, I am taking an input from a user in the form of an integer(Say 1 for Push).

For taking an input from a user continuously, I am running a while(1) loop and inside a loop asking a user to give an integer as an input for required operation.

Problem: during the execution, the program is not waiting for a user to give input and goes into infinite loop. I have tried to clear stdin using fflush but still not working.

Please look at the code below with given comments and help.

Thanks.

//Main function


int main(){


STACK marks, roll_number;      //marks and roll_number are two stacks of type STACK

//Initialize both Stacks with required size
initStack(&marks, 10);
initStack(&roll_number, 10);

int choice, marks_data;

//Menu for user to choose from available operations
printf("1. Push\n");
printf("2. Pop\n");
printf("3. Exit\n");

//Taking user input for operations
while(1){

    printf("Enter choice of Operation:\n");

    //Clearing standard input. Although not a best practice but implementing to
    //take user input
    fflush(stdin);
    // program is not stopping here and taking invalid choice
    //hence executing 'default statement' of switch case
    scanf("%d", &choice);


    switch(choice){

    case 1: printf("Enter Marks");
            scanf(" %d", &marks_data);
            push(&marks, marks_data);
            break;

    case 2: marks_data = pop(&marks);
            printf("Deleted Data : %d\n", marks_data);
            break;

    case 3: exit(0);

    default: printf("Invalid Choice of Operation !!\n");
    }

    //using to clear \n character from user and taking valid input
    printf("Press Enter Key to continue...");
    while(getchar() != '\n')
        getchar();
}

    return 0;
}
  • 2
    And what does `scanf()` return? Functions like that have return values for a reason... – Andrew Henle Apr 02 '18 at 17:05
  • 2
    `fflush(stdin);` is undefined behavior. – Christian Gibbons Apr 02 '18 at 17:13
  • Make sure Eric isn't around, he will have conniptions arguing that `fflush(stdin);` is actually valid with M$. – David C. Rankin Apr 02 '18 at 17:23
  • 1
    The problem is all previous calls to `scanf` with the `'%d'` *format specifier* leave the trailing '\n'` in `stdin` unread. (not a problems for subsequent `scanf ("%d", ..)` calls as `'%d'` ignores leading whitespace). When you call `while(getchar() != '\n')` it test true immediately and your loop continues. Just add another `getchar()` below. – David C. Rankin Apr 02 '18 at 17:26
  • @DavidC.Rankin Fortunately Microsoft is not in control of the C standard; whatever they have to say on the subject is irrelevant. – Christian Gibbons Apr 02 '18 at 17:34
  • I'm with you on that one -- but I guess to be thorough, we do need to understand where it is and isn't valid to be able to pass that wisdom along -- with the conclusion of it being all around bad practice, non-portable from windoze, and only defined for *seekable* streams for the rest of the world that you can't enforce the user provide. The `int c = getchar(); while (c != '\n' && c!= EOF) c = getchar();` is 100% portable regardless. – David C. Rankin Apr 02 '18 at 17:46
  • @ChristianGibbons: They were in enough control to make VLAs optionally, which is completely against the clear position of backwards compatibility. – too honest for this site Apr 02 '18 at 17:49
  • @DavidC.Rankin I would make the argument that it is undefined behavior in C, and that what you get on Microsoft is MSVC and not true standard-conforming C. But I guess that is starting to get pedantic. – Christian Gibbons Apr 02 '18 at 17:51
  • @Olaf Ugh, were they the ones responsible for that? Really boggled my mind to see backwards broken like that. – Christian Gibbons Apr 02 '18 at 17:52
  • @ChristianGibbons: After all they were the only ones not to have a C99 compliant compiler and specifically fighting against these C99 features loudest. Embedded compiler vendors typically have to support C99 e.g. for MISRA 2012 compatibility. Not that one should use MSVC at all. – too honest for this site Apr 02 '18 at 17:56
  • @ChristianGibbons - I agree with you 100%. There is no reason to ever use `fflush(stdin);` because 999 out of 1000 times it is either used completely wrong on a standard compliant compiler invoking *Undefined Behavior*, or you are just lucky (and unlucky) enough to be using a compiler that extends it to help save the hordes that saw it posted somewhere on the internet and included it in there code `:)` – David C. Rankin Apr 02 '18 at 18:00

1 Answers1

2

When you use scanf, you have to put your "account's hat" on and account for all characters either read from the input buffer, or left unread in the input buffer. This is especially true when mixing input between numeric and character input or when mixing input functions in your code.

In your case, you call scanf ("%d", ...) for choice and marks, but then attempt to control your loop execution with:

printf("Press Enter Key to continue...");
while(getchar() != '\n')
    getchar();

As a good scanf accountant, you know reading using the '%d' format specifier will read digits from stdin up to the first non-digit character and terminate the read, leaving the non-digit character in stdin unread. (presuming no stray characters were entered following choice or mark), that will be the '\n' character generated by pressing Enter following your previous input.

When you test while(getchar() != '\n'), the first character read is likely the '\n' character, causing your loop to test TRUE and skip the getchar() call within the loop.

The easiest solution is just to add an additional getchar() below your current one.

Next fflush(stdin) is Undefined Behavior on just about all systems except windows. On Linux, fflush(stdin) is defined, but only for seekable streams -- which only applies to stdin if a file has been redirected to your program on stdin, e.g.

./yourexe < somefile.txt

Otherwise fflush(stdin) is not defined. So you have to ask yourself -- being non-portable on everything but windows unless stdin is seekable as the result of redirection -- "Is is really good practice to use anywhere?" and "How do I force the user to redirect a file to stdin?" (you can't). So best to avoid all the way around.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85