tags:

views:

899

answers:

8

Hi, this is a "novato" question for the c programming language:

in the next code:

#include<stdio.h>

int main(void){   
  int c;   
  while((c=getchar())!= EOF)      
    putchar(c); 
  return 0;
}

I have to press ENTER to print all the letters I entered with getchar,but I don't want to do this, what I want to do is to press the letter and immediately see the the letter I introduced repeated with out press ENTER, for example, if I press the letter 'a' I want to see an other 'a' next to it, and so on:

aabbccddeeff.....

but wen I press 'a' nothing happens, I can write an others letter and the copy appears only when I press ENTER:

abcdef abcdef

How can I do this?

I am using the command cc -o example example.c under Ubuntu for compiling.

+1  A: 

By default, the C library buffers the output until it sees a return. To print out the results immediately, use fflush:

while((c=getchar())!= EOF)      
{
    putchar(c);
    fflush(stdout);
}
Andomar
However, output is part of the problem. The questioner wants to have the program read keys as they are pressed and print immediately on the screen. That's both an input and an output issue.
David Thornley
+3  A: 

getchar() is a standard function and requires you to press ENTER to get the input. Many compilers/platforms support the non-standard getch() that does not require ENTER.

Eric J.
+1 Correct, `getchar()` starts reading characters one by one only after you've pressed enter
Andomar
`getchar()` doesn't care about ENTER, it just processes whatever comes through stdin. Line buffering tends to be OS/terminal defined behaviour.
goldPseudo
@goldPseudo: True, but almost all platforms buffer input so this is the behavior you will see in most practical cases. getch(), where supported, will either manage or ignore buffering. I know some old DOS implementations bypassed OS buffering to interact directly with the hardware. Other implementations might flush stdin to get the same behavior.
Eric J.
Nonetheless, it is not `getchar()` that “requires you to press enter”, but the environment.
Benji XVI
A: 

Why are taking inputs with getchar? Is there some dynamic interaction with user?

Typically, C programs are passed with command line arguments (argv, argc style). You can also look at special file descriptor (0, 1 and 2) for STDIN and STDOUT.

Jack
getchar() is exactly for reading from STDIN. STDIN is not necessarily the keyboard, but it can also be a file.
Leonel
+3  A: 

I/O is an operating system function. In many cases, the operating system won't pass typed character to a program until ENTER is pressed. This allows the user to modify the input (such as backspacing and retyping) before sending it to the program. For most purposes, this works well, presents a consistent interface to the user, and relieves the program from having to deal with this. In some cases, it's desirable for a program to get characters from keys as they are pressed.

The C library itself deals with files, and doesn't concern itself with how data gets into the input file. Therefore, there's no way in the language itself to get keys as they are pressed; instead, this is platform-specific. Since you haven't specified OS or compiler, we can't look it up for you.

Also, the standard output is normally buffered for efficiency. This is done by the C libraries, and so there is a C solution, which is to fflush(stdout); after each character written. After that, whether the characters are displayed immediately is up to the operating system, but all the OSes I'm familiar with will display the output immediately, so that's not normally a problem.

David Thornley
+4  A: 

This depends on your OS, if you are in a UNIX like environment the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF. By disabling the canonical mode you will get the characters immediately. This is also possible on other platforms, but there is no straight forward cross-platform solution.

EDIT: I see you specified your that you use Ubuntu. I just posted something similar yesterday, but be aware that this will disable many default behaviors of your terminal.

#include<stdio.h>
#include <termios.h>            //termios, TCSANOW, ECHO, ICANON
#include <unistd.h>     //STDIN_FILENO


int main(void){   
    int c;   
    static struct termios oldt, newt;

    /*tcgetattr gets the parameters of the current terminal
    STDIN_FILENO will tell tcgetattr that it should write the settings
    of stdin to oldt*/
    tcgetattr( STDIN_FILENO, &oldt);
    /*now the settings will be copied*/
    newt = oldt;

    /*ICANON normally takes care that one line at a time will be processed
    that means it will return if it sees a "\n" or an EOF or an EOL*/
    newt.c_lflag &= ~(ICANON);          

    /*Those new settings will be set to STDIN
    TCSANOW tells tcsetattr to change attributes immediately. */
    tcsetattr( STDIN_FILENO, TCSANOW, &newt);

    /*This is your part:
    I choose 'e' to end input. Notice that EOF is also turned off
    in the non-canonical mode*/
    while((c=getchar())!= 'e')      
        putchar(c);                 

    /*restore the old settings*/
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt);


    return 0;
}

You will notice, that every character appears twice. This is because the input is immediately echoed back to the terminal and then your program puts it back with putchar() too. If you want to disassociate the input from the output, you also have to turn of the ECHO flag. You can do this by simply changing the appropriate line to:

newt.c_lflag &= ~(ICANON | ECHO);
Lucas
+1 Although tbh, this is probably not the level of code the original poster is comfortable with ;)
Andomar
Great! That's what I was looking for!
Denilson Sá
+1  A: 

Since you are working on a Unix derivative (Ubuntu), here is one way to do it - not recommended, but it will work (as long as you can type commands accurately):

echo "stty -g $(stty -g)" > restore-sanity
stty cbreak
./your_program

Use interrupt to stop the program when you are bored with it.

sh restore-sanity
  • The 'echo' line saves the current terminal settings as a shell script that will restore them.
  • The 'stty' line turns off most of the special processing (so Control-D has no effect, for example) and sends characters to the program as soon as they are available. It means you cannot edit your typing any more.
  • The 'sh' line reinstates your original terminal settings.

You can economize if 'stty sane' restores your settings sufficiently accurately for your purposes. The format of '-g' is not portable across versions of 'stty' (so what is generated on Solaris 10 won't work on Linux, or vice versa), but the concept works everywhere. The 'stty sane' option is not universally available, AFAIK (but is on Linux).

Jonathan Leffler
+4  A: 

On a linux system, you can modify terminal behaviour using the stty command. By default, the terminal will buffer all information until ENTER is pressed, before even sending it to the C program.

A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:

#include<stdio.h>

int main(void){
  int c;
  /* use system call to make terminal send all keystrokes directly to stdin */
  system ("/bin/stty raw");
  while((c=getchar())!= '.') {
    /* type a period to break out of the loop, since CTRL-D won't work raw */
    putchar(c);
  }
  /* use system call to set terminal behaviour to more normal behaviour */
  system ("/bin/stty cooked");
  return 0;
}

Please note that this isn't really optimal, since it just sort of assumes that stty cooked is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.

You can man stty for more control over the terminal behaviour, depending exactly on what you want to achieve.

goldPseudo
A: 

You could include the 'ncurses' library, and use getch() instead of getchar().

AShelly