Eingaben des Benutzers lesen und verarbeiten
Im vorherigen Kapitel haben wir uns mit dem Drucken der Programmausgabe auf dem Terminal befasst. Um jedoch mit dem Benutzer interagieren zu können, muss dies in beide Richtungen erfolgen. In diesem Kapitel wird erläutert, wie wir Eingaben lesen und interpretieren können, die der Benutzer in das Terminal eingibt. Wir haben gesehen, dass die printf-Funktion in den vorherigen Kapiteln häufig verwendet wurde. Dies ist die Standardmethode zum Schreiben von formatiertem Text in die Konsole, die Befehlszeile, über die Sie das Programm ausführen. Aber was ist, wenn Sie Eingaben vom Benutzer erhalten möchten? Wie lesen wir, was der Benutzer in die Konsole eingibt?
In den letzten Kapiteln haben wir uns die Funktion sscanf angesehen, die Werte aus einer Zeichenfolge liest. Es gibt eine äquivalente Funktion namens scanf, die Werte direkt von der Konsole liest, wie im folgenden Beispiel:
#include <stdio.h> void main (void) { char input[256]; int age; printf ("Wie ist Dein Name, User?\n"); scanf ("%s", input); printf ("Hallo, %s. Wie alt bist Du?\n", input); scanf ("%d", &age); printf ("Na gut, %s, Du siehst jung aus, für %d...\n", input, age); }
scanf funktioniert genau wie sscanf, hat jedoch ein Argument weniger, da es eher von der Konsole als von einer Zeichenfolge liest.
Dies ist jedoch nicht der beste Weg, um Konsoleneingaben zu erhalten. Es funktioniert nur dann wirklich, wenn Sie einen Benutzer haben, der genau das eingibt, was Sie erwarten. Leider neigen Benutzer dazu, Dinge einzugeben, die Sie nicht erwarten, und scanf kommt damit nicht gut zurecht. Wenn der Benutzer im obigen Code beispielsweise 257 Zeichen eingibt, wenn er nach seinem Namen gefragt wird, wird der für die Eingabezeichenfolge zugewiesene Speicherplatz überlaufen, und es können eigenartige Dinge passieren …
Ein besserer Ansatz besteht darin, jede Zeile zu lesen, die der Benutzer in eine Pufferzeichenfolge eingibt, und dann mit sscanf Werte aus dieser Zeichenfolge zu lesen. Die C-Libaryfunktion fgets ist hierfür hilfreich. Schauen Sie sich dieses Beispiel an:
#include <stdio.h> void main (void) { char input[256], name[256]; int age; printf ("Wie ist Dein Name, User?\n"); fgets (input, 256, stdin); sscanf (input, "%s", name); printf ("Hallo, %s. Wie alt bist Du?\n", name); while (1) { fgets (input, 256, stdin); if (sscanf (input, "%d", &age) == 1) break; printf ("Das ist kein Alter - versuche es nochmal!\n"); } printf ("Na gut, %s, Du siehst jung aus, für %d...\n", name, age); }
fgets nimmt drei Argumente an. Der erste ist der Puffer, in dem die Eingabe gespeichert werden soll. Die zweite ist die maximale Anzahl von Bytes, die in diesen Puffer geschrieben werden. Dies ist nützlich, um die oben erwähnte Überlaufsituation zu verhindern. Schließlich braucht es ein Argument, das angibt, woher es lesen soll. In diesem Fall ist dies auf stdin (kurz für „standard input“) eingestellt, wodurch es angewiesen wird, von der Konsole zu lesen.
Jedes Mal, wenn wir den Benutzer um Eingabe bitten, lesen wir mit fgets bis zu 256 Zeichen, was auch immer sie eingeben (bis zu dem Punkt, an dem sie die Eingabetaste drücken), und interpretieren sie dann mit sscanf. Wenn Sie nach dem Alter des Benutzers fragen, verwenden wir außerdem den von sscanf zurückgegebenen Wert (beschrieben im vorherigen Kapitel), um zu überprüfen, ob der Benutzer das eingegeben hat, was Sie erwarten, und führen eine Schleife durch, bis er eine gültige Antwort gibt. Sie können diese Methode verwenden, um so ziemlich alles zu interpretieren, was ein Benutzer eingibt, und um alle Fälle sicher zu behandeln, in denen er etwas Unerwartetes eingibt!
Sie können Ihr Programm auch auf andere Weise eingeben, indem Sie es als Parameter angeben, wenn Sie das Programm über die Befehlszeile starten. An dieser Stelle muss ich zugeben, dass ich in den letzten 8 Kapiteln nicht ganz ehrlich war. Ich habe immer die Definition der Hauptfunktion gezeigt als
void main (void)
Dies funktioniert, wie Sie gesehen haben. Das ist jedoch nicht unbedingt korrekt. Die strenge Definition von main sieht folgendermaßen aus:
int main (int argc, char *argv[])
Aber seien wir ehrlich: wenn ich Ihnen das in Kapitel 1 gezeigt hätte wären sie davongelaufen, nicht wahr? Was bedeutet das alles?
Zunächst können wir sehen, dass main eine Ganzzahl zurückgibt. Dies ist ein Erfolgs- oder Fehlercode, den einige Betriebssysteme zur Verarbeitung in einem Shell-Skript oder dergleichen verwenden können. Wenn ein Programm erfolgreich ist, gibt main normalerweise 0 zurück, und wenn es fehlschlägt, gibt es einen Fehlercode ungleich Null zurück. Für Programme, die alleine laufen, brauchen Sie sich wirklich keine Sorgen zu machen!
Was nützlicher ist, sind die beiden anderen Argumente. argc ist eine Ganzzahl, und dies ist die Anzahl der Parameter, die beim Starten des Programms in der Befehlszeile angegeben wurden. Seltsamerweise enthält die Nummer den Programmnamen selbst, sodass dieser Wert immer 1 oder mehr beträgt. Wenn Parameter angegeben wurden, sind es 2 oder mehr.
char * argv []; das ist doch verwirrend, oder? Dies ist eigentlich eine Zusammenstellung einiger Dinge, die wir bereits gesehen haben. Da ist ein * drin, also ein Zeiger. Der Typ ist char, also sind Zeichen darin und es gibt eckige Klammern, also ist es ein Array.
Dies ist eigentlich ein Array von Zeigern auf Zeichen. Jedes Element des Arrays ist eine Zeichenfolge, und jede Zeichenfolge ist einer der Parameter, die dem Programm zur Verfügung gestellt werden.
In der Praxis ist es wahrscheinlich einfacher zu verstehen:
#include <stdio.h> int main (int argc, char *argv[]) { int param = 0; while (param < argc) { printf ("Parameter %d ist %s\n", param, argv[param]); param++; } return 0; }
Oben: Die Argumente argc und argv für die Hauptfunktion können verwendet werden, um auf Parameter zuzugreifen, die in der Befehlszeile eingegeben werden, wenn das Programm ausgeführt wird.
Versuchen Sie, dies wie zuvor auszuführen, indem Sie einfach den Namen eingeben. Versuchen Sie dann, andere Dinge nach dem Namen in der Befehlszeile einzugeben, und sehen Sie, was das Programm druckt.
pi@raspberry:~ $ ./ein Parameter 0 ist ./ein
oder
pi@raspberry:~ $ ./ein Das ist ein Test Parameter 0 ist ./ein Parameter 1 ist Das Parameter 2 ist ist Parameter 3 ist ein Parameter 4 ist Test pi@raspberry:~ $
Hier ist ein Beispiel eines (sehr) einfachen Rechners, der mit Programmparametern geschrieben wurde:
#include <stdio.h> int main (int argc, char *argv[]) { int arg1, arg2; if (argc == 4) { sscanf (argv[1], "%d", &arg1); sscanf (argv[3], "%d", &arg2); if (*argv[2] == '+') printf ("%d\n", arg1 + arg2); if (*argv[2] == '-') printf ("%d\n", arg1 - arg2); if (*argv[2] == 'x') printf ("%d\n", arg1 * arg2); if (*argv[2] == '/') printf ("%d\n", arg1 / arg2); } return 0; }
Beachten Sie, dass wir *argv[2] verwenden, um das erste Zeichen des zweiten Parameters zu erhalten. Dies sollte immer nur ein einzelnes Zeichen sein. Da jedoch jedes der Argumente eine Zeichenfolge sein kann, ist argv[2] (ohne Sternchen) ein Pointer auf ein Zeichen und nicht auf das einzelne Zeichen, das für einen Vergleich mit == erforderlich ist.
echo $?
unmittelbar nach dem Ausführen eines Programms eingeben wird der Wert angezeigt, den das Programm zurückgegeben hat. Rückgabewerte sind hauptsächlich nützlich, wenn Sie Programme aus Skripten aufrufen.
Stellen Sie sicher, dass Sie die Argumente vom Operator durch Leerzeichen trennen, damit sie als separate Parameter identifiziert werden. <Progname> 2 + 2 statt <Progname> 2+2
pi@raspberry:~ $ ./calc 2 + 3 5 pi@raspberry:~ $
Oben: Der Rechner liest die beiden Werte und den Operator aus dem argv-Array und druckt das Ergebnis