Wie lösche ich den Eingabepuffer in C?

Lesezeit: 8 Minuten

Benutzeravatar von ipkiss
ipkiss

Ich habe folgendes Programm:

int main(int argc, char *argv[])
{
  char ch1, ch2;
  printf("Input the first character:"); // Line 1
  scanf("%c", &ch1); 
  printf("Input the second character:"); // Line 2
  ch2 = getchar();

  printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
  printf("ch2=%c, ASCII code = %d\n", ch2, ch2);

  system("PAUSE");  
  return 0;
}

Wie der Autor des obigen Codes erklärt hat: Das Programm wird nicht richtig funktionieren, weil es in Zeile 1, wenn der Benutzer die Eingabetaste drückt, im Eingabepuffer 2 Zeichen hinterlässt: Enter key (ASCII code 13) und \n (ASCII code 10). Daher wird in Zeile 2 die gelesen \n und wartet nicht darauf, dass der Benutzer ein Zeichen eingibt.

Okay, das habe ich. Aber meine erste Frage ist: Warum die zweite getchar() (ch2 = getchar();) liest die nicht Enter key (13)statt \n Charakter?

Als nächstes schlug der Autor 2 Möglichkeiten vor, um solche Probremsen zu lösen:

  1. verwenden fflush()

  2. schreibe eine Funktion wie diese:

    void
    clear (void)
    {    
      while ( getchar() != '\n' );
    }
    

Dieser Code hat tatsächlich funktioniert. Aber ich kann mir nicht erklären, wie es funktioniert? Denn in der While-Anweisung verwenden wir getchar() != '\n'das heißt, lesen Sie jedes einzelne Zeichen außer '\n'? wenn ja, im Eingangspuffer bleibt noch die '\n' Charakter?

  • Siehe auch: Ich kann stdin nicht leeren. Wie kann ich stdin in C leeren?

    – Gabriel Staples

    10. April um 1:20 Uhr

Benutzeravatar von jamesdlin
jamesdlin

Das Programm wird nicht richtig funktionieren, da es in Zeile 1, wenn der Benutzer die Eingabetaste drückt, 2 Zeichen im Eingabepuffer belässt: Eingabetaste (ASCII-Code 13) und \n (ASCII-Code 10). Daher liest es in Zeile 2 das \n und wartet nicht darauf, dass der Benutzer ein Zeichen eingibt.

Das Verhalten, das Sie in Zeile 2 sehen, ist richtig, aber das ist nicht ganz die richtige Erklärung. Bei Streams im Textmodus spielt es keine Rolle, welche Zeilenenden Ihre Plattform verwendet (ob Wagenrücklauf (0x0D) + Zeilenvorschub (0x0A), ein reines CR oder ein reines LF). Die C-Laufzeitbibliothek erledigt das für Sie: Ihr Programm wird nur sehen '\n' für Zeilenumbrüche.

Wenn Sie ein Zeichen eingegeben und die Eingabetaste gedrückt haben, wird dieses Eingabezeichen von Zeile 1 und dann gelesen '\n' würde von Zeile 2 gelesen werden. Siehe Ich benutze scanf %c um eine Y/N-Antwort zu lesen, aber spätere Eingaben werden übersprungen. aus der comp.lang.c-FAQ.

Zu den vorgeschlagenen Lösungen siehe (wieder aus der comp.lang.c-FAQ):

die im Grunde besagen, dass der einzige tragbare Ansatz darin besteht, Folgendes zu tun:

int c;
while ((c = getchar()) != '\n' && c != EOF) { }

Dein getchar() != '\n' Schleife funktioniert, weil Sie einmal anrufen getchar()wurde das zurückgegebene Zeichen bereits aus dem Eingabestrom entfernt.

Außerdem fühle ich mich verpflichtet, Sie von der Verwendung abzuraten scanf völlig: Warum sagt jeder, nicht zu verwenden scanf? Was sollte ich stattdessen verwenden?

  • Dies bleibt hängen und wartet darauf, dass der Benutzer die Eingabetaste drückt. Wenn Sie stdin einfach löschen möchten, verwenden Sie termios direkt. stackoverflow.com/a/23885008/544099

    – Ismael

    25. Februar 2019 um 14:39 Uhr

  • @ishmael Ihr Kommentar ergibt keinen Sinn, da das Drücken der Eingabetaste nicht erforderlich ist klar stdin; es ist erforderlich, um überhaupt erst Eingaben zu erhalten. (Und das ist das einzige Standard Möglichkeit, Eingaben in C zu lesen. Wenn Sie Schlüssel sofort lesen möchten, müssen Sie nicht standardmäßige Bibliotheken verwenden.)

    – jamesdlin

    25. Februar 2019 um 15:54 Uhr

  • @jamesdlin Unter Linux wartet getchar() darauf, dass der Benutzer die Eingabetaste drückt. Erst dann brechen sie aus der While-Schleife aus. Soweit mir bekannt ist, ist termios eine Standardbibliothek.

    – Ismael

    25. Februar 2019 um 21:04 Uhr

  • @ishmael Nein, du liegst in beiden Punkten falsch. Bei dieser Frage geht es darum, wie Sie die verbleibenden Eingaben von stdin löschen nach Lesen von Eingaben und in Standard-C Bereitstellen dieser Eingaben Erste erfordert die Eingabe einer Zeile und das Drücken der Eingabetaste. Nach diese Zeile wurde eingegeben, getchar() liest diese Zeichen und gibt sie zurück; Ein Benutzer muss kein weiteres Mal die Eingabetaste drücken. Darüber hinaus könnten Termios üblich sein auf Linuxes ist nicht Teil der C-Standardbibliothek.

    – jamesdlin

    25. Februar 2019 um 21:17 Uhr


  • was ist der grund scanf(" %c", &char_var) arbeiten und den Zeilenumbruch ignorieren, indem Sie einfach ein Leerzeichen vor dem Bezeichner %c hinzufügen?

    – Cătălina Sirbu

    29. September 2020 um 17:52 Uhr

Das geht (auch) so:

fseek(stdin,0,SEEK_END);

  • Wow… btw, sagt der Standard fseek steht zur Verfügung stdin?

    – ich

    22. Mai 2014 um 11:03 Uhr

  • Ich weiß nicht, ich glaube, es wird nicht erwähnt, aber stdin ist FILE* und fseek akzeptiert einen FILE*-Parameter. Ich habe es getestet und es funktioniert unter Mac OS X, aber nicht unter Linux.

    – Ramy Al Zuhouri

    22. Mai 2014 um 11:07 Uhr

  • Bitte erkläre. Es wäre eine großartige Antwort, wenn der Autor Auswirkungen dieser Methode schreiben würde. Gibt es Probleme?

    – Eva Alex

    28. Oktober 2015 um 7:35 Uhr

  • @EvAlex: Es gibt viele Probleme damit. Wenn es auf Ihrem System funktioniert, großartig; wenn nicht, dann ist es nicht verwunderlich, da nichts garantiert, dass es funktioniert, wenn die Standardeingabe ein interaktives Gerät ist (oder ein nicht suchbares Gerät wie eine Pipe oder ein Socket oder ein FIFO, um nur einige andere Möglichkeiten zu nennen, wie es möglich ist scheitern).

    – Jonathan Leffler

    15. September 2016 um 5:08 Uhr

  • Warum sollte es SEEK_END sein? Können wir stattdessen SEEK_SET verwenden? Wie verhält sich die FP-stdin?

    – Rajesh

    3. März 2017 um 11:33 Uhr

Eine portable Möglichkeit, bis zum Ende einer Zeile aufzuräumen, die Sie bereits versucht haben, teilweise zu lesen, ist:

int c;

while ( (c = getchar()) != '\n' && c != EOF ) { }

Dies liest und verwirft Zeichen, bis es kommt \n was das Ende der Datei signalisiert. Es prüft auch gegen EOF falls der Eingabestrom vor dem Ende der Zeile geschlossen wird. Die Art von c muss sein int (oder größer), um den Wert halten zu können EOF.

Es gibt keine portable Methode, um herauszufinden, ob es nach der aktuellen Zeile noch weitere Zeilen gibt (falls nicht, dann getchar blockiert die Eingabe).

  • warum while((c=getchar())!=EOF); funktioniert nicht? Es ist eine Endlosschleife. Die Position von EOF in stdin kann nicht verstanden werden.

    – Rajesh

    3. März 2017 um 15:57 Uhr

  • @Rajesh Das würde klar, bis der Eingabestrom geschlossen ist, was nicht der Fall sein wird, wenn später weitere Eingaben kommen

    – MM

    3. März 2017 um 21:45 Uhr


  • @Rajesh Ja, du hast Recht. Wenn auf stdin nichts zu leeren ist, wenn dies aufgerufen wird, wird es blockiert (hängt), da es in einer Endlosschleife gefangen ist.

    – Jason Henochs

    13. Juli 2017 um 21:31 Uhr

  • @AbhishekMane Aber ein Byte ist 8 Bit und 256 dauert 9 Bit. Sie können keinen 8-Bit-Wert plus einen zusätzlichen Flag-Wert verarbeiten, wenn Sie das Ergebnis von getchar() einem char zuweisen. Ebenfalls, stdio.h hat #define EOF (-1). C hat char, signed char, unsigned char, und char kann je nach Architektur zwischen 0..255 oder -128..127 liegen. man getchar ist sehr explizit: “fgetc() liest das nächste Zeichen aus dem Stream und gibt es als unsigned char cast in ein int oder EOF am Ende der Datei oder bei einem Fehler zurück.” Also (int) -1 oder (int) 0..255. Wenn Sie es in eine char-Variable füllen, werden wichtige Informationen verworfen.

    – Paul_Pedant

    19. März um 10:07 Uhr

  • @Paul_Pedant hat es verstanden. Vielen Dank. EOF ist kein Charakter. getchar() kehrt zurück char(0,1,2,...255) + EOF Damit umzugehen EOF nur Rückgabetyp von getchar(_) ist int . So C muss sein int Rechts ?

    – Abhishek Mähne

    22. März um 8:26 Uhr

Benutzeravatar von Dmitri
Dimitri

Die Linien:

int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
    ;

liest nicht nur die Zeichen vor dem Zeilenvorschub ('\n'). Es liest alle Zeichen im Stream (und verwirft sie) bis einschließlich der nächste Zeilenvorschub (oder EOF wird angetroffen). Damit der Test wahr ist, muss er zuerst den Zeilenvorschub lesen; Wenn die Schleife stoppt, war der Zeilenvorschub das letzte gelesene Zeichen, aber es wurde gelesen.

Warum es einen Zeilenvorschub anstelle eines Wagenrücklaufs liest, liegt daran, dass das System den Zeilenumbruch in einen Zeilenvorschub übersetzt hat. Wenn die Eingabetaste gedrückt wird, signalisiert dies das Ende der Zeile … aber der Stream enthält stattdessen einen Zeilenvorschub, da dies die normale Zeilenende-Markierung für das System ist. Das kann plattformabhängig sein.

Auch mit fflush() auf einem Eingabestrom funktioniert nicht auf allen Plattformen; Zum Beispiel funktioniert es im Allgemeinen nicht unter Linux.

Aber ich kann mir nicht erklären, wie es funktioniert? Denn in der While-Anweisung verwenden wir getchar() != '\n'das heißt, lesen Sie jedes einzelne Zeichen außer '\n'?? wenn ja, im Eingangspuffer bleibt noch die '\n' Charakter??? Verstehe ich etwas falsch??

Was Sie vielleicht nicht wissen, ist, dass der Vergleich stattfindet nach getchar() entfernt das Zeichen aus dem Eingabepuffer. Also, wenn Sie die erreichen '\n'es wird verbraucht und dann Sie brechen aus der Schleife aus.

Du kannst es versuchen

scanf("%c%*c", &ch1);

wobei %*c den Zeilenumbruch akzeptiert und ignoriert

eine weitere Methode anstelle von fflush(stdin), die undefiniertes Verhalten aufruft, das Sie schreiben können

while((getchar())!='\n');

Vergiss das Semikolon nach der While-Schleife nicht

Benutzer-Avatar von nowox
nowox

Ich bin überrascht, dass das niemand erwähnt hat:

scanf("%*[^\n]");

1421870cookie-checkWie lösche ich den Eingabepuffer in C?

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

Privacy policy