Teil 15 „Making your programs work“

Der C-Kurs
Antworten
Benutzeravatar
bodo
User
Beiträge: 319
Registriert: 14.02.2007, 17:21
Kontaktdaten:

Teil 15 „Making your programs work“

Beitrag von bodo » 13.11.2010, 14:08

C für BASIC-Programmierer

Arbeiten mit dem z88dk Cross-Compiler

von Jens Sommerfeld und Bodo Wenzel

Teil 15

Es ist schon interessant, dass in Vickers' Handbuch erst jetzt das Kapitel „Making your programs work“ kommt. Denn ist das nicht das Ziel aller unserer Bemühungen seit dem Anfang? Egal, dieses Mal geht es um Flussdiagramme und Fehlersuche. Wir werden dabei die Flussdiagramme auslassen, denn die kennt ihr ja schon...

Die einfachste Art ein Programm zu debuggen ist, an geeigneten Stellen Ausgaben mit den Werten wichtiger Variablen einzufügen. Das ist zunächst völlig unabhängig von der Programmiersprache; ja selbst bei der Programmierung der winzigen Mikrocontroller kann man den einen oder anderen Portpin in bestimmten Rhythmen wackeln lassen. In C machen wir das natürlich mit printf().

Für ein Beispiel nehmen wir eine weitere, neue Steuerstruktur, die ihr noch nicht kennt, die Mehrfachverzweigung switch-case. Das folgende Programm soll vom Benutzer eine Auswahl fordern und dann entsprechend arbeiten, aber irgendwie funktioniert es nicht wie gewünscht:

Code: Alles auswählen

#include <stdio.h>

int main(void) {
    int ergebnis;

    ergebnis = 0;
    for (;;) {
        char eingabe[10];
        int wert;

        puts("BITTE WAEHLEN SIE:");
        puts(".     ENDE");
        puts("=     ERGEBNIS AUSGEBEN");
        puts("+ZAHL WERT FUER ADDITION EINGEBEN");
        puts("-ZAHL WERT FUER SUBTRAKTION EINGEBEN");
        gets(eingabe);
        puts("");

        sscanf(eingabe + 1, "%d", &wert);

        switch (eingabe[0]) {
        case '.':
            return 0;
        case '=':
            printf("ERGEBNIS = %d\n", ergebnis);
        case '+':
            ergebnis += wert;
        case '-':
            ergebnis -= wert;
        }
    }
}
Bevor wir an die Fehlersuche gehen, zunächst eine kurze Erläuterung zu switch-case. Nach dem ersten Schlüsselwort wird in runden Klammern ein ganzzahliger Ausdruck angegeben. Hier können wir auch ein Zeichen wählen, weil ja Zeichen in ganzen Zahlen codiert sind. Nach den runden Klammern kommt ein Block mit geschweiften Klammern. Dieser kann verschiedene Fälle des Ausdrucks unterscheiden, hier sind aber nur Konstanten (ganze Zahlen oder einzelne Zeichen) erlaubt. Zum Beispiel geht folgendes:

Code: Alles auswählen

    switch (int_var * 3 – 1) {
    case 12:
        /* Anweisungen, wenn der Ausdruck gleich 12 ist. */
    case 3:
        /* Anweisungen, wenn der Ausdruck gleich 3 ist. */
    case 81:
        /* Anweisungen, wenn der Ausdruck gleich 81 ist. */
}
Zwischen zwei case's müssen nicht unbedingt Anweisungen stehen.

Was macht unser Programm jetzt falsch? Zunächst einmal sieht alles richtig aus, aber wir können keine Werte addieren lassen. Das Ergebnis ändert sich nicht! Also bauen wir erstmal eine Ausgabe ein, die uns den aktuellen Stand des Ergebnisses anzeigt:

Code: Alles auswählen

    ...
    printf("AKTUELL = %d\n", ergebnis);
    puts("BITTE WAEHLEN SIE:");
    ...
Hm, das hilft uns noch nicht weiter, sondern bestätigt nur die Beobachtungen. Vielleicht sollten wir nach jeder Änderung des Ergebnisses den Inhalt der Variablen kontrollieren?

Code: Alles auswählen

    ...
    case '+':
        ergebnis += wert;
        printf("AKTUELL = %d\n", ergebnis);
    case '-':
        ergebnis -= wert;
        printf("AKTUELL = %d\n", ergebnis);
    ...
Ah ja, wenn wir jetzt einen Wert addieren lassen wollen, erhalten wir zwei Ausgaben! Und wenn wir uns das Ergebnis ausgeben lassen, wird uns auch zweimal unsere Testausgabe angezeigt. Es scheint so, als ob zwar der switch entsprechend dem ersten Zeichen der Eingabe den Beginn der Anweisungen richtig wählt, aber alle Anweisungen danach ausgeführt werden...

Und das ist auch tatsächlich der Fall – und es ist so richtig. Die Mehrfachverzweigung soll so arbeiten, damit z.B. wie in folgendem Beispiel mehrere Auswahlen zu denselben Anweisungen führen:

Code: Alles auswählen

    switch (zeichen) {
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
        /* Anweisungen für die Vokale */
    ...
Wenn wir es nicht verhindern, „fällt der Programmfluss durch“ in den nächsten Zweig. Die Verhinderung geschieht mit einem Schlüsselwort, das wir schon von den Schleifen kennen: break.

Die Mehrfachverzweigung kennt noch ein weiteres Schlüsselwort, das einen Zweig für den Fall einleitet, dass kein anderer Zweig passt. Dieses Schlüsselwort heißt default; es ist guter Stil, es immer anzugeben, auch wenn gar nichts ausgeführt wird! Ein Beispiel:

Code: Alles auswählen

    switch (menu) {
    case 1:
        /* Anweisungen für den ersten Menüpunkt */
        break;
    case 2:
        /* Anweisungen für den zweiten Menüpunkt */
        break;
    case 3:
        /* Anweisungen für den dritten Menüpunkt */
        break;
    default:
        break;
    }
Hausaufgaben
  1. Korrigiert das Beispielprogramm, so dass es korrekt funktioniert.
  2. Erweitert das Beispielprogramm um eine default-Verzweigung, die eine falsche Eingabe mit der Ausgabe des Hilfetextes beantwortet. Dann ist auch die immer wiederkehrende Ausgabe innerhalb der Schleife nicht mehr nötig.
B0D0: Real programmers do it in hex.

Antworten