Das bis hierher Gelernte wollen wir in einer kleinen Übung vertiefen: wir programmieren einen einfachen Taschenrechner. Damit das Ganze überschaubar bleibt, sollen nur die Grundrechenarten unterstützt werden - ohne Punkt- vor Strichrechnung.
Wir beginnen mit der main-Funktion mit einigen Variablendeklarationen und der Ausgabe einer Überschrift. Endlich bekommt die Funktion auch einen Kommentar:
Code: Alles auswählen
#include <stdio.h>
#include <string.h>
/* Main.
Returns an error code (== 0: ok, != 0: error).
*/
int main(void)
{
float fInput, fAkku;
char op, currentOp;
char continueLoop;
char formatted[20];
printf("Mini-Taschenrechner\n\n");
Die Variable fInput verwenden wir für die Benutzereingabe, mit fAkku wird gerechnet. Dann brauchen wir noch zwei Variablen für den Operator, eine Hilfsvariable für die Schleife und einen String (d.h. einen char-Array) für die formatierte Ausgabe von Zahlen.
Dann folgt ein wenig Initialisierung:
Und schließlich die Schleife und der Rest der main-Funktion:
Code: Alles auswählen
do {
printf("Zahl : ");
scanf("%f", &fInput);
printf("Operation: ");
currentOp = getchar();
currentOp = getchar();
switch (op) {
case '\0':
fAkku = fInput;
break;
case '+':
fAkku = fAkku + fInput;
break;
case '-':
fAkku = fAkku - fInput;
break;
case '*':
fAkku = fAkku * fInput;
break;
case '/':
fAkku = fAkku / fInput;
break;
default:
continueLoop = 0;
}
formatNumber(fAkku, formatted);
printf(" %s\n", formatted);
op = currentOp;
} while (currentOp != '=' && continueLoop);
return 0;
}
In der Schleife gibt der Benutzer eine Zahl ein, die via scanf als float-Wert eingelesen wird (daher der Format-String
"%f"). Der Wert landet in der Variablen
fInput, deren Adresse wir scanf als zweites Argument übergeben.
Dann fordern wir den Benutzer auf einen Operator einzugeben. Den lesen wir mit
getchar ein, dann muss der Operator nicht mit der Enter-Taste bestätigt werden. Es sieht hier so aus, als würden wir den Operator zweimal einlesen, aber der erste getchar-Aufruf räumt nur etwas "Müll" aus dem Tastaturpuffer, den scanf zurückgelassen hat. Der zweite getchar-Aufruf ist der, der uns den Operator liefert.
In der switch-Anweisung sieht man, welche Operatoren erlaubt sind: +, -, *, / und =. Der case-Zweig mit dem '\0' wird nur beim ersten Durchlauf erreicht, weil op mit '\0' initialisiert wurde. Im ersten Durchlauf gibt es auch noch nichts zu rechnen; wir speichern nur die erste Zahl in
fAkku.
In jedem weiteren Durchlauf wird fAkku abhängig vom Operator mit dem nächsten Eingabewert verknüpft. Wird ein ungültiger Operator eingegeben, dann bricht die Schleife ab, indem
continueLoop auf 0 gesetzt wird (continueLoop wurde mit 1 initialisiert). Aber continueLoop ist doch eine char-Variable, wie kann sie dann auf eine Zahl wie 0 oder 1 gesetzt werden? Der C-Compiler ist hier recht tolerant; wenn man einer char-Variablen einen Zahlwert zuweist, dann nimmt er das klaglos als ASCII-Code an, solange der Wertebereich nicht überschritten wird. Für vorzeichenbehaftete char ist das -128 bis +127, für unsigned char 0 bis 255. Wir verwenden hier den char als verkappte Boolean-Variable.
Die while-Bedingung gibt an, wann die Schleife weiterlaufen soll. Ist der aktuelle Operand ein '=', dann wird die Schleife regulär beendet.
Eine Sache fehlt noch: Die Ausgabe des jeweiligen Zwischenergebnisses erfolgt nicht direkt durch
printf("%f", fAkku);, sondern es wird die Funktion formatNumber aufgerufen. Die macht die Zahl etwas hübscher, indem sie sie in einen String umwandelt.
Schauen wir uns die Funktion mal genauer an. Sie muss vor der main-Funktion, aber nach den #include-Anweisungen eingefügt werden:
Code: Alles auswählen
/* Formats a float by cutting off the zeroes at the end.
If there are only zeroes after the decimal point, then
the decimal point is cut off, too.
Parameters: f the float value to format
formatted a character buffer to hold the float as string
*/
void formatNumber(float f, char *formatted) {
char *s;
sprintf(formatted, "%f", f);
s = formatted + strlen(formatted);
--s;
while (s != formatted) {
if (*s != '0') {
if (*s != '.') {
++s;
}
*s = '\0';
break;
}
--s;
}
}
Wir übergeben ihr den zu formatierenden float-Wert und einen Pointer (die Adresse) auf eine Zeichenkette, in die die formatierte Zahl abgelegt werden soll. Das ist unser char-Array
formatted.
Zu Beginn wird die Zahl f in eine Zeichenkette umgewandelt. Dies geschieht mit der Funktion
sprintf, die genauso funktioniert wie printf, nur landet die Ausgabe nicht auf dem Bildschirm, sondern in der String-Variablen, die als erstes Argument übergeben wird. Danach ist alles wie bei printf: der Format-String, dann die Variablen, die die Format-Platzhalter mit Werten füllen.
Die folgende Schleife schneidet alle unnötigen Nullen am Ende der Zahl, nach dem Dezimalpunkt ab. Der String wird von rechts beginnend Zeichen für Zeichen durchlaufen, bis ein Zeichen ungleich '0' gefunden wird. Das folgende Zeichen wird mit dem String-Abschlusszeichen '\0' überschrieben, wodurch der String verkürzt wird. Eine Sonderbehandlung gibt es noch für den Dezimalpunkt: Damit eine Zahl wie 2.000000 nicht zu 2. resultiert, wird hier nicht das folgende Zeichen, sondern der Dezimalpunkt selbst mit dem Abschlusszeichen überschrieben. Das Ergebnis ist dann einfach eine 2 ohne den verwaisten Dezimalpunkt.