Wie vermeide ich es, die Eingabetaste mit getchar() zu drücken, um nur ein einzelnes Zeichen zu lesen?
Lesezeit: 8 Minuten
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.
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
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
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
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):
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
AShelly
Sie könnten die ‘ncurses’-Bibliothek einbeziehen und verwenden getch() Anstatt von getchar().
14200000cookie-checkWie vermeide ich es, die Eingabetaste mit getchar() zu drücken, um nur ein einzelnes Zeichen zu lesen?yes
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