Zum Inhalt springen
C Anfรคnger 25 min

if, switch & Schleifen

C-Kontrollstrukturen klassisch: if/else, switch mit break, for, while und do-while sowie goto und continue.

Aktualisiert:
Inhaltsverzeichnis

Kontrollstrukturen in C

C hat die klassischen Kontrollstrukturen, die in vielen Sprachen nachgebildet sind. Nichts Ueberraschendes - aber ein paar C-spezifische Fallstricke.

if / else

int alter = 18;

if (alter >= 18) {
    printf("Volljaehrig\n");
} else if (alter >= 16) {
    printf("Fast volljaehrig\n");
} else {
    printf("Zu jung\n");
}

Regeln:

  • Klammern () um die Bedingung sind Pflicht
  • {} sind technisch optional bei einer Zeile - trotzdem immer setzen!
  • true / false gibt es mit stdbool.h, sonst: 0 = false, alles andere = true

Die = vs ==-Falle

if (alter = 18) { /* ... */ }    // AUTSCH - Zuweisung statt Vergleich!
if (alter == 18) { /* ... */ }   // richtig

Ein klassischer C-Bug. Compiler-Warnungen (-Wall) finden das:

warning: suggest parentheses around assignment used as truth value

Tipp: Manche Profis schreiben den konstanten Wert links - if (18 == alter) - das verhindert versehentliche Zuweisungen.

Ternaerer Operator

const char *text = (alter >= 18) ? "volljaehrig" : "minderjaehrig";
printf("%s\n", text);

switch

int tag = 3;

switch (tag) {
    case 1:
        printf("Montag\n");
        break;
    case 2:
    case 3:
    case 4:
        printf("Mitte der Woche\n");
        break;
    case 5:
        printf("Freitag\n");
        break;
    default:
        printf("Wochenende\n");
}

Kritisch wichtig: Jeder case muss mit break; enden - sonst faellt die Ausfuehrung durch zum naechsten Case. Das ist eine haeufige Fehlerquelle.

Bewusstes Fall-Through

Manchmal ist Fall-Through Absicht:

switch (c) {
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
        printf("Vokal\n");
        break;
    default:
        printf("Konsonant\n");
}

Was geht in switch?

Nur Ganzzahl-Typen und char. Keine Strings. Fuer Strings brauchst du if/else if:

if (strcmp(eingabe, "ja") == 0) {
    // ...
} else if (strcmp(eingabe, "nein") == 0) {
    // ...
}

while

int n = 10;
while (n > 0) {
    printf("%d\n", n);
    n--;
}

do-while

Laeuft mindestens einmal:

int eingabe;
do {
    printf("Gib eine Zahl ein: ");
    scanf("%d", &eingabe);
} while (eingabe != 0);

Man erkennt do-while am Semikolon nach while(...).

for

Die klassische Zaehlschleife:

for (int i = 0; i < 5; i++) {
    printf("%d\n", i);
}

Jeder Teil ist optional:

for (;;) {              // Endlosschleife
    // ...
    if (fertig) break;
}

Ueber Arrays iterieren

int zahlen[] = {10, 20, 30, 40, 50};
int n = sizeof(zahlen) / sizeof(zahlen[0]);

for (int i = 0; i < n; i++) {
    printf("%d\n", zahlen[i]);
}

C hat kein range-based for wie C++. Du musst den Index selbst fuehren.

break und continue

for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) continue;   // gerade ueberspringen
    if (i > 7) break;            // abbrechen bei > 7
    printf("%d\n", i);           // 1, 3, 5, 7
}

break bricht nur eine Schleife ab

Bei verschachtelten Schleifen:

int gefunden = 0;
for (int x = 0; x < 5 && !gefunden; x++) {
    for (int y = 0; y < 5; y++) {
        if (suche(x, y)) {
            gefunden = 1;
            break;     // bricht nur innere Schleife
        }
    }
}

Oder du nimmst eine Hilfsfunktion und return.

goto - der Notnagel

C erlaubt goto - die meisten Sprachen nicht mehr. Es ist selten noetig, aber in C manchmal die sauberste Loesung fuer Fehlerbehandlung:

int daten_verarbeiten(void) {
    FILE *f = fopen("daten.txt", "r");
    if (f == NULL) goto fehler;

    char *puffer = malloc(1024);
    if (puffer == NULL) goto datei_schliessen;

    // ... Arbeit ...
    if (fehler_aufgetreten) goto alles_freigeben;

    free(puffer);
    fclose(f);
    return 0;

alles_freigeben:
    free(puffer);
datei_schliessen:
    fclose(f);
fehler:
    return -1;
}

Das ist der Cleanup-auf-einem-Pfad-Pattern, das in Kernel-Code verbreitet ist. Ausserhalb solcher Kontexte meidest du goto.

Kurzschluss-Evaluation

Die logischen Operatoren kurzschliessen:

// && bricht ab, sobald false kommt
if (zeiger != NULL && zeiger->wert > 0) {
    // sicher - zeiger wird nur dereferenziert, wenn nicht NULL
}

// || bricht ab, sobald true kommt
if (x == 0 || 10 / x > 1) {
    // sicher - Division durch Null wird vermieden
}

Praktisches Beispiel

#include <stdio.h>

int main(void) {
    int zahlen[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    int n = sizeof(zahlen) / sizeof(zahlen[0]);

    int max = zahlen[0];
    int gerade = 0;

    for (int i = 0; i < n; i++) {
        // Maximum finden
        if (zahlen[i] > max) {
            max = zahlen[i];
        }

        // Gerade zaehlen
        if (zahlen[i] % 2 == 0) {
            gerade++;
        }
    }

    printf("Max: %d\n", max);
    printf("Gerade Zahlen: %d von %d\n", gerade, n);

    // Ausgabe mit Klassifizierung
    for (int i = 0; i < n; i++) {
        int z = zahlen[i];
        const char *kategorie;

        switch (z) {
            case 1: case 2: case 3:
                kategorie = "klein";
                break;
            case 4: case 5: case 6:
                kategorie = "mittel";
                break;
            default:
                kategorie = "gross";
        }

        printf("  %d (%s)\n", z, kategorie);
    }

    return 0;
}

Zusammenfassung

  • if/else - keine impliziten bool-Konvertierungen beachten, == statt =
  • switch - immer break; nach jedem Case (oder bewusst Fall-Through nutzen)
  • for, while, do-while klassisch
  • Kein range-for - du fuehrst den Index selbst
  • break/continue wirken nur eine Schleife, goto fuer Cleanup-Patterns
  • Kurzschluss-Evaluation von && und || fuer sichere Checks nutzen

Im naechsten Kapitel: Funktionen und ihr Scope in C.

Zurรผck zum C Kurs