¿Cómo evitar presionar Enter con getchar() para leer un solo carácter?

5 minutos de lectura

avatar de usuario
javier

En el siguiente código:

#include <stdio.h>

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

tengo que presionar Ingresar para imprimir todas las letras que ingresé con getcharpero no quiero hacer esto, lo que quiero hacer es presionar la letra e inmediatamente ver la letra que introduje repetida sin presionar Ingresar. Por ejemplo, si presiono la letra ‘a’ quiero ver otra ‘a’ junto a ella, y así sucesivamente:

aabbccddeeff.....

Pero cuando presiono ‘a’ no pasa nada, puedo escribir otras letras y la copia aparece solo cuando presiono Ingresar:

abcdef
abcdef

¿Cómo puedo hacer esto?

estoy usando el comando cc -o example example.c bajo Ubuntu para compilar.

  • esto depende mucho de cómo su sistema operativo y su terminal procesen la entrada. si especifica su entorno operativo, probablemente obtendrá mejores respuestas.

    – goldPseudo

    25 de noviembre de 2009 a las 17:48

  • La respuesta dada en cplusplus.com/forum/articles/19975 funciona en Windows usando WinAPI.

    usuario1202095

    10 de febrero de 2012 a las 12:58

  • stackoverflow.com/q/421860/270315

    – jwaliszko

    29 de septiembre de 2013 a las 16:26

  • Ver también: entrada de teclado sin bloqueo C

    – Gabriel grapas

    3 de febrero a las 22:54

avatar de usuario
oroPseudo

En un sistema Linux, puede modificar el comportamiento de la terminal usando el stty dominio. De forma predeterminada, el terminal almacenará en búfer toda la información hasta que Ingresar se presiona, incluso antes de enviarlo al programa C.

Un ejemplo rápido, sucio y no particularmente portátil para cambiar el comportamiento desde el propio programa:

#include<stdio.h>
#include<stdlib.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;
}

Tenga en cuenta que esto no es realmente óptimo, ya que simplemente supone que stty cooked es el comportamiento que desea cuando el programa sale, en lugar de verificar cuáles eran las configuraciones originales del terminal. Además, dado que todo el procesamiento especial se omite en modo sin procesar, muchas secuencias clave (como CTRL-C o CTRL-D) en realidad no funcionarán como esperas sin procesarlos explícitamente en el programa.

Puede man stty para tener más control sobre el comportamiento de la terminal, dependiendo exactamente de lo que quieras lograr.

  • Utilizando system es una mala idea

    – Zafiro_Brick

    13 de agosto de 2020 a las 21:45

  • Demasiado crudo… Estaba buscando una solución que me permitiera no esperar a ENTER. Esta solución frena todas las funcionalidades del terminal de entrada.

    – A B C

    30 de agosto de 2020 a las 14:46


avatar de usuario
RobertS apoya a Mónica Cellio

Cómo evitar presionar Ingresar con getchar()?

En primer lugar, la entrada del terminal suele ser de línea o completamente almacenada en búfer. Esto significa que el sistema operativo almacena la entrada real de la terminal en un búfer. Por lo general, este búfer se descarga en el programa cuando, por ejemplo, \n fue señalado/proporcionado en stdin. Esto es fe hecho por una prensa para Ingresar.

getchar() está justo al final de la cadena. No tiene la capacidad de influir realmente en el proceso de almacenamiento en búfer.


¿Cómo puedo hacer esto?

Abandone getchar() en primer lugar, si no desea utilizar llamadas al sistema específicas para cambiar el comportamiento de la terminal explícitamente como se explica en las otras respuestas.

Desafortunadamente, no existe una función de biblioteca estándar y, por lo tanto, no hay una forma portátil de vaciar el búfer en la entrada de un solo carácter. Sin embargo, existen soluciones basadas en implementación y no portátiles.


En Windows/MS-DOS, existen los getch() y getche() funciones en el conio.h archivo de encabezado, que hace exactamente lo que desea: lea un solo carácter sin la necesidad de esperar a que la nueva línea vacíe el búfer.

La principal diferencia entre getch() y getche() es eso getch() no muestra inmediatamente el carácter de entrada real en la consola, mientras que getche() hace. El adicional "e" representa eco.

Ejemplo:

#include <stdio.h>
#include <conio.h>   

int main (void) 
{
    int c;

    while ((c = getche()) != EOF)
    {
        if (c == '\n')
        {
            break;
        }

        printf("\n");
    }

    return 0;
}

En Linux, una forma de obtener procesamiento y salida de caracteres directos es usar el cbreak() y echo() opciones y el getch() y refresh() rutinas en la biblioteca ncurses.

Tenga en cuenta que debe inicializar el llamado pantalla estándar con el initscr() y cerramos lo mismo con el endwin() rutinas

Ejemplo:

#include <stdio.h>
#include <ncurses.h>   

int main (void) 
{
    int c;

    cbreak(); 
    echo();

    initscr();

    while ((c = getch()) != ERR)
    {
        if (c == '\n')
        {
            break;
        }

        printf("\n");
        refresh();
    }

    endwin();

    return 0;
}

Nota: debe invocar el compilador con el -lncurses opción, para que el enlazador pueda buscar y encontrar la biblioteca ncurses.

getchar() es una función estándar que en muchas plataformas requiere que presione ENTER para obtener la entrada, porque la plataforma almacena la entrada hasta que se presiona esa tecla. Muchos compiladores/plataformas admiten getch() no estándar que no se preocupa por ENTER (omite el almacenamiento en búfer de la plataforma, trata ENTER como una tecla más).

avatar de usuario
la noche brilla

Me gusta la respuesta de Lucas, pero me gustaría elaborarla un poco. Hay una función incorporada en termios.h llamado cfmakeraw() cual hombre describe como:

cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]

Básicamente, esto hace lo mismo que sugirió Lucas y más, puede ver las banderas exactas que establece en las páginas del manual: termios(3).

caso de uso

int c = 0;
static struct termios oldTermios, newTermios;

tcgetattr(STDIN_FILENO, &oldTermios);
newTermios = oldTermios;

cfmakeraw(&newTermios);

tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios);

switch (c) {
    case 113: // q
        printf("\n\n");
        exit(0);
        break;
    case 105: // i
        printf("insert\n");
        break;
    default:
        break;

  • Tenga en cuenta que cfmakeraw() es una extensión no estándar y no portátil para POSIX termios.h y no está necesariamente disponible.

    –Andrew Henle

    3 de diciembre de 2019 a las 15:47

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad