0

I am trying to learn how input/output works, and was curious about something regarding this basic code from a textbook:

#include <stdio.h>
/* copy input to output; 1st version */

int main()
{
int c;

c = getchar();
while (c != EOF) {
    putchar(c);
    c = getchar();
}
}

After I use gcc to turn this code into an executable, it runs completely fine. However, within the executable, whenever I press "enter", all my input is sent out, and thus also printed on the next line as output. How could I set things up so that so I can get the new line, '\n', that I want out of enter, without signalling that I want to send my input? I am currently working in the Linux MATE terminal, if that is an influencing factor.

Br0f1st
  • 49
  • 4
  • 3
    In that case, *what* would signal that you want to send the input to your program? – P.P Aug 09 '20 at 21:07
  • 1
    Perhaps you just want to use a heredoc to generate the input. That would allow you to enter multiple lines of text before the program executes. – William Pursell Aug 09 '20 at 21:21
  • 1
    Change `stdin,stdout` to operate in non-buffered mode. See[Disable buffering for stdin and stdout using setvbuf()](https://stackoverflow.com/q/19365655/2410359) – chux - Reinstate Monica Aug 09 '20 at 22:28

2 Answers2

5

When you run this command in the terminal (without redirection), typically, the input you are typing is echoed by the terminal and only sent to your program after you press enter. Then the loop is will start reading each character you typed and display it. Afterwards, it again waits for input which the terminal only sends after you press enter.

Try redirecting your input from a file and see the difference.

prompt$ ./yourprogram < somefile

If you want to be able to read each character immediately as typed by the user, you need to disable canonical mode (line buffering) in your program using the tcsetattr function. However, it is advisable to first record the old value using tcgetattr and restore it afterwards. However, when your input is coming from a terminal you will not see an EOF (hence I added the q option to quit). If this is what you are looking for, you may also want to disable echoing the characters (commented line).

#include <stdio.h>
#include <termios.h>
#include <unistd.h>

int main() {
  struct termios old_tio, new_tio;
  tcgetattr(STDIN_FILENO, &old_tio);
  new_tio=old_tio;
  new_tio.c_lflag &=(~ICANON);
  /* new_tio.c_lflag &=(~ECHO); */
  tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);

  int c;
  c = getchar();
  while (c != EOF) {
    putchar(c);
    c = getchar();
    if (c=='q') break;
  }

  tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
}
Tom
  • 749
  • 4
  • 16
3

Standard input is buffered in the sense that the program does not receive the input until you send a newline or until you send EOF (CtrlD in some terminal emulators).

If you need to handle input as it arrives (key strokes), you need to use something else (i.e. outside of the standard). For instance, the ncurses library is a popular solution for Linux CLI applications.

Acorn
  • 24,970
  • 5
  • 40
  • 69