Wie vermeide ich es, die Eingabetaste mit getchar() zu drücken, um nur ein einzelnes Zeichen zu lesen?

Lesezeit: 8 Minuten

Javiers Benutzeravatar
Javier

Im nächsten Code:

#include <stdio.h>

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

Ich muss drücken Eintreten um alle Buchstaben auszudrucken, mit denen ich eingegeben habe getcharaber ich möchte das nicht tun, was ich tun möchte, ist, auf den Buchstaben zu drücken und sofort zu sehen, dass der von mir eingegebene Buchstabe wiederholt wird, ohne zu drücken Eintreten. Wenn ich zum Beispiel den Buchstaben „a“ drücke, möchte ich ein weiteres „a“ daneben sehen und so weiter:

aabbccddeeff.....

Aber wenn ich ‘a’ drücke, passiert nichts, ich kann andere Buchstaben schreiben und die Kopie erscheint nur, wenn ich drücke Eintreten:

abcdef
abcdef

Wie kann ich das machen?

Ich verwende den Befehl cc -o example example.c unter Ubuntu zum Kompilieren.

  • Dies hängt stark davon ab, wie Ihr Betriebssystem und Terminal Eingaben verarbeiten. Wenn Sie Ihre Betriebsumgebung angeben, erhalten Sie wahrscheinlich bessere Antworten.

    – GoldPseudo

    25. November 2009 um 17:48 Uhr

  • Die Antwort unter cplusplus.com/forum/articles/19975 funktioniert unter Windows mit der WinAPI.

    Benutzer1202095

    10. Februar 2012 um 12:58 Uhr

  • stackoverflow.com/q/421860/270315

    – jwaliszko

    29. September 2013 um 16:26 Uhr

  • Siehe auch: C nicht blockierende Tastatureingabe

    – Gabriel Staples

    3. Februar um 22:54 Uhr

Benutzeravatar von Lucas
Lukas

Dies hängt von Ihrem Betriebssystem ab. Wenn Sie sich in einer UNIX-ähnlichen Umgebung befinden, ist das ICANON-Flag standardmäßig aktiviert, sodass die Eingabe bis zur nächsten gepuffert wird '\n' oder EOF. Durch Deaktivieren des kanonischen Modus erhalten Sie die Zeichen sofort. Dies ist auch auf anderen Plattformen möglich, aber es gibt keine einfache plattformübergreifende Lösung.

BEARBEITEN: Ich sehe, Sie haben angegeben, dass Sie Ubuntu verwenden. Ich habe gerade gestern etwas Ähnliches gepostet, aber seien Sie sich bewusst, dass dadurch viele Standardverhalten Ihres Terminals deaktiviert werden.

#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;
}

Sie werden feststellen, dass jedes Zeichen zweimal vorkommt. Dies liegt daran, dass die Eingabe sofort an das Terminal zurückgesendet wird und Ihr Programm sie dann zurücksetzt putchar() zu. Wenn Sie den Eingang vom Ausgang trennen möchten, müssen Sie auch das ECHO-Flag ausschalten. Sie können dies tun, indem Sie einfach die entsprechende Zeile ändern in:

newt.c_lflag &= ~(ICANON | ECHO); 

  • +1 Obwohl dies wahrscheinlich nicht die Codeebene ist, mit der sich das Originalposter wohl fühlt;)

    – Andomar

    25. November 2009 um 19:21 Uhr

  • Groß! Das habe ich gesucht!

    – Denilson Sá Maia

    28. April 2010 um 1:42 Uhr

  • Danke für die Hilfe zusammen mit den ausführlichen Kommentaren, es hat mein Problem gelöst.

    – Kaminsknator

    29. April 2016 um 19:33 Uhr

  • Es ist unglaublich, dass etwas so Einfaches so schwer zu erreichen und nicht portierbar ist.

    – Pedro77

    18. Februar 2020 um 20:08 Uhr

Benutzeravatar von goldPseudo
GoldPseudo

Auf einem Linux-System können Sie das Terminalverhalten mithilfe von ändern stty Befehl. Standardmäßig puffert das Terminal alle Informationen bis Eintreten gedrückt wird, bevor es überhaupt an das C-Programm gesendet wird.

Ein schnelles, schmutziges und nicht besonders tragbares Beispiel, um das Verhalten innerhalb des Programms selbst zu ändern:

#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;
}

Bitte beachten Sie, dass dies nicht wirklich optimal ist, da es das einfach annimmt stty cooked ist das gewünschte Verhalten beim Beenden des Programms, anstatt zu überprüfen, was die ursprünglichen Terminaleinstellungen waren. Da auch alle speziellen Verarbeitungen im Raw-Modus übersprungen werden, werden viele Tastenfolgen (wie z STRG-C oder STRG-D) funktionieren nicht so, wie Sie es erwarten, ohne sie explizit im Programm zu verarbeiten.

Du kannst man stty für mehr Kontrolle über das Endgeräteverhalten, je nachdem, was Sie erreichen wollen.

  • Verwenden system ist eine schlechte Idee.

    – Saphir_Ziegel

    13. August 2020 um 21:45 Uhr

  • Zu viel Rohmaterial …. Ich suchte nach einer Lösung, die es mir ermöglicht, nicht auf ENTER zu warten. Diese Lösung bremst alle Funktionalitäten der Eingangsanschlüsse.

    – ABC

    30. August 2020 um 14:46 Uhr


Benutzeravatar von Eric J
Erich J.

getchar() ist eine Standardfunktion, bei der Sie auf vielen Plattformen die EINGABETASTE drücken müssen, um die Eingabe zu erhalten, da die Plattform die Eingabe puffert, bis diese Taste gedrückt wird. Viele Compiler/Plattformen unterstützen das nicht standardmäßige getch(), das sich nicht um ENTER kümmert (umgeht die Pufferung der Plattform, behandelt ENTER wie nur eine weitere Taste).

  • +1 Richtig, getchar() beginnt mit dem Lesen von Zeichen nacheinander erst, nachdem Sie die Eingabetaste gedrückt haben

    – Andomar

    25. November 2009 um 17:51 Uhr

  • getchar() ENTER ist egal, es verarbeitet einfach alles, was durch stdin kommt. Die Leitungspufferung ist in der Regel ein vom Betriebssystem/Terminal definiertes Verhalten.

    – GoldPseudo

    25. November 2009 um 17:55 Uhr

  • @goldPseudo: Stimmt, aber fast alle Plattformen puffern Eingaben, so dass dies das Verhalten ist, das Sie in den meisten praktischen Fällen sehen werden. getch(), sofern unterstützt, verwaltet oder ignoriert die Pufferung. Ich weiß, dass einige alte DOS-Implementierungen die Betriebssystempufferung umgangen haben, um direkt mit der Hardware zu interagieren. Andere Implementierungen können stdin leeren, um das gleiche Verhalten zu erhalten.

    – Eric J.

    25. November 2009 um 18:02 Uhr

  • Trotzdem ist es nicht getchar() das „erfordert, dass Sie die Eingabetaste drücken“, sondern die Umgebung.

    – Benji XVI

    25. November 2009 um 21:28 Uhr

  • Sehr knapp und leicht verständlich. Andere am besten bewertete Antworten werfen nur über überwältigende unnötige technische Details.

    – mzoz

    13. Januar 2017 um 3:29 Uhr

E/A ist eine Funktion des Betriebssystems. In vielen Fällen übergibt das Betriebssystem eingegebene Zeichen erst dann an ein Programm, wenn die EINGABETASTE gedrückt wird. Dadurch kann der Benutzer die Eingabe ändern (z. B. Zurücksetzen und erneutes Eingeben), bevor er sie an das Programm sendet. Für die meisten Zwecke funktioniert dies gut, bietet dem Benutzer eine konsistente Schnittstelle und entlastet das Programm davon, sich damit befassen zu müssen. In einigen Fällen ist es für ein Programm wünschenswert, Zeichen von Tasten zu erhalten, während sie gedrückt werden.

Die C-Bibliothek selbst befasst sich mit Dateien und kümmert sich nicht darum, wie Daten in die Eingabedatei gelangen. Daher gibt es in der Sprache selbst keine Möglichkeit, Tasten zu erhalten, wenn sie gedrückt werden; Stattdessen ist dies plattformspezifisch. Da Sie kein Betriebssystem oder Compiler angegeben haben, können wir es nicht für Sie nachschlagen.

Außerdem wird die Standardausgabe normalerweise aus Effizienzgründen gepuffert. Dies wird von den C-Bibliotheken erledigt, und daher gibt es eine C-Lösung, die to fflush(stdout); nach jedem geschriebenen Zeichen. Ob die Zeichen danach sofort angezeigt werden, hängt vom Betriebssystem ab, aber alle Betriebssysteme, mit denen ich vertraut bin, zeigen die Ausgabe sofort an, sodass dies normalerweise kein Problem darstellt.

Ich mag Lucas Antwort, aber ich würde sie gerne etwas ausarbeiten. Da ist eine eingebaute Funktion drin termios.h genannt cfmakeraw() die Mann beschreibt als:

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. [...]

Dies macht im Grunde dasselbe wie das, was Lucas vorgeschlagen hat, und Sie können die genauen Flags, die es setzt, in den Manpages sehen: Fristen(3).

Anwendungsfall

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;

  • Beachten Sie, dass cfmakeraw() ist eine nicht portable, nicht standardmäßige Erweiterung von Posix termios.h und ist nicht unbedingt vorhanden.

    – Andreas Henle

    3. Dezember 2019 um 15:47 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Da Sie an einem Unix-Derivat (Ubuntu) arbeiten, ist hier eine Möglichkeit, dies zu tun – nicht empfohlen, aber es wird funktionieren (solange Sie Befehle genau eingeben können):

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

Verwenden Sie Interrupt, um das Programm zu stoppen, wenn es Sie langweilt.

sh restore-sanity
  • Die Zeile „echo“ speichert die aktuellen Terminaleinstellungen als Shell-Skript, das sie wiederherstellt.
  • Die ‘stty’-Zeile schaltet den größten Teil der speziellen Verarbeitung aus (so Steuerung-D hat zum Beispiel keine Wirkung) und sendet Zeichen an das Programm, sobald sie verfügbar sind. Das bedeutet, dass Sie Ihre Eingabe nicht mehr bearbeiten können.
  • Die ‘sh’-Zeile stellt Ihre ursprünglichen Terminaleinstellungen wieder her.

Sie können sparen, wenn ‘stty sane’ Ihre Einstellungen für Ihre Zwecke ausreichend genau wiederherstellt. Das Format von „-g“ ist nicht über Versionen von „stty“ hinweg portierbar (was unter Solaris 10 generiert wird, funktioniert also nicht unter Linux oder umgekehrt), aber das Konzept funktioniert überall. Die Option „stty sane“ ist nicht allgemein verfügbar, AFAIK (aber unter Linux).

  • Beachten Sie, dass cfmakeraw() ist eine nicht portable, nicht standardmäßige Erweiterung von Posix termios.h und ist nicht unbedingt vorhanden.

    – Andreas Henle

    3. Dezember 2019 um 15:47 Uhr

Benutzeravatar von AShelly
AShelly

Sie könnten die ‘ncurses’-Bibliothek einbeziehen und verwenden getch() Anstatt von getchar().

1420000cookie-checkWie vermeide ich es, die Eingabetaste mit getchar() zu drücken, um nur ein einzelnes Zeichen zu lesen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy