Console I/O : printf & scanf not occurring in expected order

138 views Asked by At
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void eat() // clears stdin upto and including \n OR EOF
{
    int eat;while ((eat = getchar()) != '\n' && eat != EOF);
}

int main(){

    printf("\n COMMAND : "); char cmd[21]=""; scanf("%20s",cmd);

    if(strcmp(cmd,"shell")==0||strcmp(cmd,"sh")==0)
    {
        getchar(); // absorb whitespace char separating 'shell' and the command, say 'ls'
        while(1)
        {
            printf("\n sh >>> "); // print prompt
            char shellcmd[1024]=""; // str to store command
            scanf("%1023[^\n]",shellcmd); eat(); // take input of command and clear stdin

            if(strcmp("close",shellcmd)==0||strcmp("x",shellcmd)==0)
                break;
            else
                system(shellcmd);
        }
    }
}

In the code, some anomalous behavior is occurring which I'm unable to catch.

Upon entering sh ls and pressing [ENTER], the expected response is:

  1. 1st scanf() stored sh in cmd[] and leaves ls\n in stdin.
  2. getchar() takes up the space.
  3. printf() prints \n sh >>> to Terminal
  4. second scanf() stores ls in shellcmd[], leaves \n in stdin
  5. eat() reads the \n from stdin, leaving it empty
  6. system("ls") is executed

I.e. results should be like this:

 COMMAND : sh ls

 sh >>>
 file1 file 2 file3 ...

 sh >>> | (cursor)

BUT

What I get:

COMMAND : sh ls

file1 file2 file3 ...
 sh >>> 
 sh >>> | 

Apparently, the 2nd scanf() and shell() are executing before printf() , or at least that's my assumption.

What's amiss?

Compiled on Clang and GCC with cc -Wall -Wextra -pedantic and tested on bash on MacOS as well as Linux

1

There are 1 answers

9
Roberto Caboni On BEST ANSWER

As you can find in the man page:

If a stream refers to a terminal (as stdout normally does) it is line buffered

So you might experience a delay in seeing the message printed by printf whenever it doesn't contain a newline. On the other end, the previos message is displayed as soon as the leading newline of the next printf is sent.

Solutions:

  1. Add a newline at the end your message printf("\n sh >>> \n");

  2. Force the current buffer to be displayed even in absence of a newline by calling flush() function (fflush(stdout))

  3. Change the current stdout buffering behavior with setvbuf() function

    setvbuf(stdout,NULL,_IONBF,0);