Im nächsten Code:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
Ich muss drücken Enter, um alle Buchstaben zu drucken, mit getchar
denen ich eingegeben habe , aber ich möchte dies nicht tun. Ich möchte den Buchstaben drücken und sofort sehen, dass der von mir eingeführte Buchstabe wiederholt wird, ohne zu drücken Enter. Wenn ich zum Beispiel den Buchstaben 'a' drücke, möchte ich ein anderes '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 Enter:
abcdef
abcdef
Wie kann ich das machen?
Ich benutze den Befehl cc -o example example.c
unter Ubuntu zum Kompilieren.
Antworten:
Auf einem Linux-System können Sie das Terminalverhalten mit dem
stty
Befehl ändern . Standardmäßig puffert das Terminal alle Informationen, bis sie Entergedrückt werden, bevor es überhaupt an das C-Programm gesendet wird.Ein schnelles, schmutziges und nicht besonders portables 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 nur davon ausgegangen wird, dass dies
stty cooked
das gewünschte Verhalten beim Beenden des Programms ist, anstatt die ursprünglichen Terminaleinstellungen zu überprüfen. Da alle speziellen Verarbeitungen im Raw-Modus übersprungen werden, funktionieren viele Tastenfolgen (wie STRG-C oder STRG-D ) nicht so, wie Sie es erwarten, ohne sie explizit im Programm zu verarbeiten.Sie können
man stty
das Terminalverhalten besser steuern, je nachdem, was Sie genau erreichen möchten.quelle
system
ist eine schlechte Idee.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 zum nächsten
'\n'
oder gepuffert wirdEOF
. Wenn Sie den kanonischen Modus deaktivieren, erhalten Sie die Zeichen sofort. Dies ist auch auf anderen Plattformen möglich, es gibt jedoch keine einfache plattformübergreifende Lösung.EDIT: Ich sehe, Sie haben angegeben, dass Sie Ubuntu verwenden. Ich habe gestern gerade etwas Ähnliches gepostet, aber sei dir bewusst, dass dies viele Standardverhalten deines Terminals deaktiviert.
#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 erscheint. Dies liegt daran, dass die Eingabe sofort an das Terminal zurückgesendet wird und Ihr Programm sie dann auch wieder zurückgibt
putchar()
. Wenn Sie die Eingabe von der Ausgabe trennen möchten, müssen Sie auch das ECHO-Flag deaktivieren. Sie können dies tun, indem Sie einfach die entsprechende Zeile ändern in:quelle
getchar () ist eine Standardfunktion, bei der Sie auf vielen Plattformen die EINGABETASTE drücken müssen, um die Eingabe abzurufen, 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 für ENTER interessiert (umgeht die Plattformpufferung und behandelt ENTER wie einen anderen Schlüssel).
quelle
getchar()
beginnt das Lesen von Zeichen nacheinander, nachdem Sie die Eingabetaste gedrückt habengetchar()
ENTER ist mir egal, es verarbeitet nur alles, was durch stdin kommt. Die Zeilenpufferung ist in der Regel ein vom Betriebssystem / Terminal definiertes Verhalten.getchar()
, dass Sie die Eingabetaste drücken müssen, sondern die Umgebung.E / A ist eine Betriebssystemfunktion. In vielen Fällen übergibt das Betriebssystem ein eingegebenes Zeichen erst an ein Programm, wenn die EINGABETASTE gedrückt wird. Auf diese Weise kann der Benutzer die Eingabe (z. B. Backspacing und Retyping) ändern, bevor er sie an das Programm sendet. Für die meisten Zwecke funktioniert dies gut, bietet dem Benutzer eine konsistente Benutzeroberfläche und entlastet das Programm davon, sich damit befassen zu müssen. In einigen Fällen ist es wünschenswert, dass ein Programm Zeichen von Tasten abruft, wenn diese 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 keinen 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 durchgeführt, und so gibt es eine C-Lösung, die
fflush(stdout);
nach jedem geschriebenen Zeichen steht. Danach hängt es vom Betriebssystem ab, ob die Zeichen sofort angezeigt werden, aber alle mir bekannten Betriebssysteme zeigen die Ausgabe sofort an, sodass dies normalerweise kein Problem darstellt.quelle
Ich mag Lucas Antwort, aber ich würde es gerne ein bisschen ausarbeiten. Es gibt eine eingebaute Funktion in
termios.h
namens,cfmakeraw()
die der Mensch 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 entspricht im Wesentlichen dem, was Lucas vorgeschlagen hat, und Sie können die genauen Flags auf den Manpages sehen: termios (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;
quelle
cfmakeraw()
eine nicht tragbare, nicht standardmäßige Erweiterung von POSIX isttermios.h
und nicht unbedingt verfügbar ist.Da Sie an einem Unix-Derivat (Ubuntu) arbeiten, gibt es 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 Sie sich langweilen.
Sie können sparen, wenn 'stty sane' Ihre Einstellungen für Ihre Zwecke ausreichend genau wiederherstellt. Das Format von '-g' ist nicht für alle Versionen von 'stty' 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).
quelle
Sie können die Bibliothek 'ncurses' einschließen und
getch()
stattdessen verwendengetchar()
.quelle
Ja, Sie können dies auch unter Windows tun. Hier ist der folgende Code, der die conio.h-Bibliothek verwendet
#include <iostream> //basic input/output #include <conio.h> //provides non standard getch() function using namespace std; int main() { cout << "Password: "; string pass; while(true) { char ch = getch(); if(ch=='\r'){ //when a carriage return is found [enter] key cout << endl << "Your password is: " << pass <<endl; break; } pass+=ch; cout << "*"; } getch(); return 0; }
quelle
Ich hatte dieses Problem / diese Frage in einer Aufgabe, an der ich gerade arbeite. Dies hängt auch davon ab, von welchem Eingang Sie greifen. ich benutze
um Eingaben zu erhalten, während das Programm ausgeführt wird, muss dies der dem Befehl zugeordnete Dateistream sein.
Auf der Ubuntu-Maschine muss ich testen / zielen, es war mehr als nur erforderlich
system( "stty -raw" );
oder
system( "stty -icanon" );
Ich musste das Flag --file sowie den Pfad zum Befehl wie folgt hinzufügen:
system( "/bin/stty --file=/dev/tty -icanon" );
Jetzt ist alles kopaketisch.
quelle
Dieser Code hat bei mir funktioniert. Achtung: Dies ist nicht Teil der Standardbibliothek, auch wenn die meisten Compiler (ich verwende GCC) dies unterstützen.
#include <stdio.h> #include <conio.h> int main(int argc, char const *argv[]) { char a = getch(); printf("You typed a char with an ASCII value of %d, printable as '%c'\n", a, a); return 0; }
Dieser Code erkennt den ersten Tastendruck.
quelle
Erstens ist der Terminaleingang üblicherweise entweder leitungsgebunden oder vollständig gepuffert. Dies bedeutet, dass das Betriebssystem die tatsächliche Eingabe vom Terminal in einem Puffer speichert. Normalerweise wird dieser Puffer in das Programm geleert, wenn zB
\n
signalisiert / bereitgestellt wurdestdin
. Dies wird zB durch eine Presse gemacht Enter.getchar()
ist gerade am Ende der Kette. Es ist nicht in der Lage, den Pufferungsprozess tatsächlich zu beeinflussen.Ditch
getchar()
in erster Linie, wenn Sie keine spezifischen Systemaufrufe verwenden möchten, um das Verhalten des Terminals explizit zu ändern, wie in den anderen Antworten erläutert.Es gibt leider keine Standardbibliotheksfunktion und damit keine tragbare Möglichkeit, den Puffer bei der Eingabe einzelner Zeichen zu leeren. Es gibt jedoch implementierungsbasierte und nicht portable Lösungen.
In Windows / MS-DOS gibt es die
getch()
undgetche()
-Funktionen in derconio.h
Header-Datei, die genau das tun, was Sie wollen - ein einzelnes Zeichen lesen, ohne darauf warten zu müssen, dass die neue Zeile den Puffer leert.Der Hauptunterschied zwischen
getch()
undgetche()
besteht darin, dassgetch()
das eigentliche Eingabezeichen in der Konsole nicht sofort ausgegeben wird, während dies dergetche()
Fall ist. Das zusätzliche"e"
steht für Echo .Beispiel:
#include <stdio.h> #include <conio.h> int main (void) { int c; while ((c = getche()) != EOF) { if (c == '\n') { break; } printf("\n"); } return 0; }
In Linux, eine Möglichkeit , direkte Zeichenverarbeitung und Ausgabe zu erhalten , ist es, die zu verwenden
cbreak()
undecho()
Optionen und diegetch()
undrefresh()
Routinen in der ncurses-Bibliothek.Beachten Sie, dass Sie den sogenannten Standardbildschirm mit dem initialisieren
initscr()
und diesen mit denendwin()
Routinen schließen müssen.Beispiel:
#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; }
Hinweis: Sie müssen den Compiler mit der
-lncurses
Option aufrufen , damit der Linker die ncurses-Bibliothek suchen und finden kann.quelle
Standardmäßig puffert die C-Bibliothek die Ausgabe, bis eine Rückgabe angezeigt wird. Verwenden Sie zum sofortigen Ausdrucken der Ergebnisse
fflush
:while((c=getchar())!= EOF) { putchar(c); fflush(stdout); }
quelle