2017-02-16 4 views
0

Aus irgendeinem Grunde scanf liest den Charakter, aber das Programm nicht fortgesetzt vorbei an der while-Schleife verwendet, um den Charakter selbst zu bestätigen, obwohl die Zeichen gültig sind. Manchmal funktioniert es und manchmal nicht. Das Seltsame ist, dass ich nichts anderes mache. Irgendwelche Ideen?Scanf Charakter in C

do 
{ 
    printf("Enter \"p\" if you want to sort and shuffle a list of players or enter \"s\" if you want to sort a list of slots: "); // prompt 
    scanf("%c", &tmp); 
} while (tmp != 'p' && tmp != 's'); 

neuer Code:

printf("Enter 'p' if you want to sort and shuffle a list of players or enter 's' if you want to sort a list of slots:"); // prompt 
tmp = getchar(); 

printf("%c ",tmp); 
if (tmp == 'p') 
{ 
    size = readPlayerFile(players); // calling readPlayerFile function 
    shufflePlayers(players, size); // call shufflePlayers function 
    sortPlayers(players, size); // call sortPlayers function 
} 
else if (tmp == 's') 
{ 
    printf("hello"); 
    size = readSlotFile(slots); // calling readSlotFile function 
    sortSlot(slots, size); // call sortSlots function 

} 
+2

Haben Sie ein grundlegendes Debugging durchgeführt? Wie mit einem Debugger und/oder debug print-Anweisungen, um herauszufinden, welche Werte tmp nimmt, wenn es funktioniert und wann nicht? – kaylum

+0

Es funktioniert gut auf meinem System. – Jarvis

+1

Was hast du vorher gelesen? Hat es einen Zeilenumbruch in der Eingabe hinterlassen? Sie sollten 'if (scanf ("% c ", & tmp)! = 1) {... handle error ...}' in Betracht ziehen, wo das Leerzeichen vor dem '% c' kein Zufall ist - es überspringt Leerzeichen (Leerzeichen, Tabs, Zeilenumbrüche) und wartet darauf, dass etwas anderes (ein 'p' oder ein' s') eingegeben wird. –

Antwort

1

Die einfachste Möglichkeit ist, einen führenden Platz auf das Format-String in scanf() hinzuzufügen. Zum Beispiel, wenn Sie den Benutzer auffordern wollen ein Zeichen erneut eingeben, wenn schlechter Eingang versehen ist, können Sie dies tun: obwohl

#include <stdio.h> 

int main(void) 
{ 

    char tmp; 
    printf("Enter \"p\" if you want to sort and shuffle a list of players " 
      "or enter \"s\" if you want to sort a list of slots: "); // prompt 
    while (scanf(" %c", &tmp) != 1 || (tmp != 'p' && tmp != 's')) { 
     printf("Please enter \"p\" or \"s\": "); 
    } 
    printf("You chose %c\n", tmp); 

    printf("Choose \"a\"scending or \"d\"escending sort: "); 
    while (scanf(" %c", &tmp) != 1 || (tmp != 'a' && tmp != 'd')) { 
     printf("Please enter \"a\" or \"d\": "); 
    } 
    printf("You chose %c\n", tmp); 

    return 0; 
} 

Es gibt ein Problem mit diesem einfachen Ansatz. Wenn der Benutzer "aaap" tritt dann würde die resultierende Ausgabe sein:

Enter "p" if you want to sort and shuffle a list of players or enter "s" if you want to sort a list of slots: aaap 
Please enter "p" or "s": Please enter "p" or "s": Please enter "p" or "s": You chose p 
Choose "a"scending or "d"escending sort: 

Oder, schlimmer noch, wenn der Benutzer ein richtiges erstes Zeichen von anderen Zeichen gefolgt eintritt, wie "sfffa":

Enter "p" if you want to sort and shuffle a list of players or enter "s" if you want to sort a list of slots: sfffa 
You chose s 
Choose "a"scending or "d"escending sort: Please enter "a" or "d": Please enter "a" or "d": Please enter "a" or "d": You chose a 

Weil scanf() Blätter Nicht übereinstimmende Zeichen im Eingabestrom müssen vor dem erneuten Lesen des Eingabestreams behandelt werden. In der einfachen Lösung, die " %c" verwendet, verursacht der anfängliche Raum scanf(), führende Leerzeichen zu überspringen, aber alle anderen Zeichen werden aufgenommen. Und in der realen Welt kann man nicht darauf zählen, dass der Benutzer kooperiert, indem er sich gut benimmt.

Eine typische, tragbar, ist getchar() Lösung in einer Schleife zu verwenden, um den Eingangsstrom nach einer Eingabeoperation zu löschen. Möglicherweise müssen Sie die Eingangsschleife Logik ein wenig ändern, dies zu tun:

#include <stdio.h> 

... 

char tmp; 
int c; 
int scanf_ret; 

do { 
    printf("Enter \"p\" if you want to sort and shuffle a list of players " 
      "or enter \"s\" if you want to sort a list of slots: "); // prompt 
    scanf_ret = scanf("%c", &tmp); 
    while ((c = getchar()) != '\n' && c != EOF) { 
     continue;     // discard extra characters 
    } 
} while (scanf_ret != 1 || (tmp != 'p' && tmp != 's')); 

Nach dem Aufruf von scanf() wird eine Schleife eingetreten, dass liest und verwirft alle Zeichen im Eingabestrom verbleiben. Beachten Sie, dass c ein int ist, und dass EOF explizit in der Schleife getestet wird. Die getchar() Funktion kann im Fehlerfall EOF zurückgeben, oder wenn der Benutzer über die Tastatur EOF signalisiert, oder wenn die Eingabe von einer Datei umgeleitet wurde. Wenn in solchen Fällen kein Test für EOF ausgeführt wird, würde dies zu einer Endlosschleife führen.

Diese Lösung funktioniert, auch wenn der Benutzer nicht vorhersehbar Eingang eintritt, da der Eingangsstrom immer nach der Eingabe immer gelöscht wird.Beachten Sie, dass das führende Leerzeichen in der Formatzeichenfolge nicht benötigt wird. Eine andere Lösung wäre, fgets() zu verwenden, um eine Eingabezeile in einen Puffer zu lesen, und sscanf(), um den Puffer zu analysieren.

#include <stdio.h> 
#include <stdlib.h> 

... 

char buffer[1000]; 
char tmp; 
int sscanf_ret; 

do { 
    printf("Enter \"p\" if you want to sort and shuffle a list of players " 
      "or enter \"s\" if you want to sort a list of slots: "); // prompt 
    if (fgets(buffer, sizeof buffer, stdin) == NULL) { 
     fprintf(stderr, "Error in fgets()\n"); 
     exit(EXIT_FAILURE); 
    } 
    sscanf_ret = sscanf(buffer, "%c", &tmp); 
} while (sscanf_ret != 1 || (tmp != 'p' && tmp != 's')); 

Die fgets() Funktion ruft eine ganze Zeile der Eingabe, die durch die Neuen-Zeile oder erhält (sizeof buffer) - 1 Zeichen aus dem Eingangsstrom, wenn der Puffer nicht groß genug ist, um alle Zeichen in dem Eingangsstrom zu halten, und ein \0 terminator . Durch die Bereitstellung eines großzügig bemessenen Puffers sollte dies gut funktionieren. Ein Benutzer könnte immer noch eine sehr große Anzahl von Zeichen eingeben, und während dies den Puffer nicht überläuft, würden Zeichen in dem Eingabestrom für die nächste Leseoperation zurückbleiben, um zu finden. Um solche Probleme zu vermeiden, wenn gibt es zusätzliche Zeichen zurückgelassen, sollte der Eingangsstrom nach dem Aufruf an fgets() mit der getchar() Schleife von oben gelöscht werden.

Alle diese Techniken haben ihren Platz. Offensichtlich sind die letzten beiden viel robuster als die ersten, und da es unwahrscheinlich ist, dass ein Benutzer 999 Zeichen an der Eingabeaufforderung (einschließlich der Zeilenschaltung) eingibt, sind sie fast gleichberechtigt. Um alle Überraschungen zu vermeiden, ist es jedoch am besten, den Eingabestream nach der Benutzereingabe explizit zu löschen.

+0

danke für die lange Erklärung ich wusste das nicht! Ich habe den Validator losgeworden, weil ich immer noch Probleme hatte, also habe ich nur die Eingabeaufforderung und tmp = getchar(); und aus irgendeinem Grund wird es immer noch nicht funktionieren Ich versuche, den Charakter direkt nach dem Lesen zu drucken und es wird immer noch nicht funktionieren. – james

+0

Wenn Sie dies noch nicht tun, müssen Sie möglicherweise einen Zeilenumbruch drucken, um den Ausgabepuffer auf dem Bildschirm zu löschen: 'printf ("% c \ n ", tmp);'. Wenn Sie am Ende Ihrer Frage einen Bearbeitungsabschnitt mit dem neuen Code hinzufügen, werde ich einen Blick darauf werfen. –

+0

danke Ich werde das jetzt versuchen Ich habe die Frage mit dem neuen Code bearbeitet, ich versuche es zu vereinfachen, um zu versuchen, das Problem zu finden. das seltsame ist, dass es mit Zahlen funktioniert, die sie als Zeichen lesen, aber nicht mit p oder s – james

0

Erstens scanf() hinterlässt ein \n im Eingangspuffer, und es bleibt im Eingang die nächsten Puffer sie aufgerufen wird. Sie benötigen einen Raum zu Ihrem Formatspezifizierer hinzuzufügen:

scanf(" %c", &tmp) 

Leerzeichen zu überspringen, die Zeilenumbrüche, Leerzeichen oder Tabulatoren sein können.

Zweitens müssen Sie Rückkehr von scanf() zu überprüfen, um sicherzustellen, nur ein Zeichen gefunden wurde.

Ihr Code kann dann wie folgt aussehen:

#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
    char temp; 

    do { 
     printf("Enter \"p\" if you want to sort and shuffle a list of players or enter \"s\" if you want to sort a list of slots: "); // prompt 
     if (scanf(" %c", &tmp) != 1) { 
      printf("Invalid character\n"); 
      exit(EXIT_FAILURE); 
     } 
    } while (tmp != 'p' && tmp != 's'); 

    return 0; 
}