2

I am trying to make a loop that will run infinitely without user input, until 'Enter' is pressed. This is the simplified version of my program:

do {

printf("Hello\n");

}while(!getchar());

When I compile and run the program only output one 'Hello' and the program will not continue, until Enter is pressed then the program will exit. May I know which part am I wrong?

Thank you.

zhengyue
  • 33
  • 1
  • 5
  • On which operating system? – Basile Starynkevitch Mar 15 '14 at 07:02
  • I am trying to make a loop that will run infinitely without user input, until 'Enter' is pressed. - When I compile and run the program only output one 'Hello' and stucked, until Enter is pressed. - Looks like you got what you need – Andrey Chernukha Mar 15 '14 at 07:02
  • pressing "Enter" is also kinda of user input..:P – Kamlesh Arya Mar 15 '14 at 07:04
  • By dear boy it is called buffering. http://stackoverflow.com/questions/4327942/non-buffering-stdin-reading – Ed Heal Mar 15 '14 at 07:04
  • Hi, thanks for the reply though. What I want was the program to repeatedly printing "Hello" until I press enter. However what the program do now is only output One "Hello" and stucked, until I press Enter to exit it. May I know which part am I wrong that the program will not print repeatedly? @BasileStarynkevitch: Linux – zhengyue Mar 15 '14 at 07:05
  • @user3326504 yes it stuck because going to take input might be this not possible which you want in `c`.because always terminal want `\n`. – Jayesh Bhoi Mar 15 '14 at 07:08

4 Answers4

2

It is not so easy. Your problem is that the standard I/O functions are synchronous. Your getchar is waiting for some input (a line of input to be precise) and it blocks execution of program until Enter is pressed. To continue execution without blocking you need to use asynchronous I/O operations or select (or poll). Select allows you to detect whether the next I/O operation would block or not. Look at the documentation of select and try this:

#include<stdio.h>
#include<unistd.h>
#include <sys/select.h>

int main() {
    fd_set          s;
    struct timeval  timeout;

    timeout.tv_sec = 0;
    timeout.tv_usec = 100000;

    do {
        printf("Hello\n"); 
        fflush(stdout);
        FD_ZERO(&s);
        FD_SET(STDIN_FILENO, &s);
        select(STDIN_FILENO+1, &s, NULL, NULL, &timeout);
    } while (FD_ISSET(STDIN_FILENO, &s) == 0);

}
Marian
  • 7,402
  • 2
  • 22
  • 34
  • That probably won't work as intented, since the kernel is buffering the tty input line. – Basile Starynkevitch Mar 15 '14 at 07:19
  • And `select` is old-fashion, use instead [poll(2)](http://www.man7.org/linux/man-pages/man2/poll.2.html) – Basile Starynkevitch Mar 15 '14 at 07:25
  • @BasileStarynkevitch The program is working and on my Linux box. The choice between poll and select is a question of taste. – Marian Mar 15 '14 at 07:41
  • Thank you for the extra explanation on async IO and blocking. I had a doubt before if it is possible to be done in a sequential program, and I thought of making another thread to stop this current one. Still learning, but thanks. – zhengyue Mar 15 '14 at 09:33
  • @user3326504 If you only want to interrupt your program, the standard way is to catch SIGINT and SIGTERM signals (i.e. Control-C coming from your terminal) and to perform your own actions on those signals. See the manual page for the function `signal` to set up your own signal handling. – Marian Mar 15 '14 at 11:52
0

On Linux, the terminal is a tty which is generally somehow buffered by the kernel. Read the tty demystified and about line discipline.

You might use ncurses or readline

Read getchar(3) man page (e.g. with man 3 getchar in a terminal). It says that

getchar() return the character read as an unsigned char cast to an int or EOF on end of file or error.

So your test is wrong, you probably want while(getchar() != EOF) which does not wait for some keyboard input. In other words getchar is always blocking on user input. You could give an end-of-file with Ctrl D

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

Your program gets stucked because getchar() function is awaiting for input. When you input something (enter), getchar() returns non-zero value, so the while statement becomes wrong and thats why the loop is ended.

NuPagadi
  • 1,410
  • 1
  • 11
  • 31
0

need to figure out difference of Canonical vs. non-canonical terminal input

As you tried i think on canonical terminal so what's limitation you already now.So i just explain you about non-canonical terminal

For non-canonical input - think vi or vim or whatever — you press a character, and it is immediately available to the program. You aren't held up until you hit return. The system does no editing of the characters; they are made available to the program as soon as they are typed. It is up to the program to interpret things appropriately. Now, vim does do a number of things that look a bit like canonical input. For example, backspace moves backwards, and in input mode erases what was there. But that's because vim chooses to make it behave like that.

So you need to use non-canonical flavor.

Community
  • 1
  • 1
Jayesh Bhoi
  • 24,694
  • 15
  • 58
  • 73
  • I think that "non-canonical" is called "raw input mode" – Basile Starynkevitch Mar 15 '14 at 07:26
  • @BasileStarynkevitch i think so but for more info look http://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html#Noncanonical-Input – Jayesh Bhoi Mar 15 '14 at 07:28
  • Hi, thank you for your reply. I'm compiling this on linux terminal but i suppose the same problem occurs also on other OS? I have read before on canonical and non, but i do not know how to apply it on this case. Thanks. – zhengyue Mar 15 '14 at 09:36