if, switch & Schleifen
C-Kontrollstrukturen klassisch: if/else, switch mit break, for, while und do-while sowie goto und continue.
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/falsegibt es mitstdbool.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- immerbreak;nach jedem Case (oder bewusst Fall-Through nutzen)for,while,do-whileklassisch- Kein range-for - du fuehrst den Index selbst
break/continuewirken nur eine Schleife,gotofuer Cleanup-Patterns- Kurzschluss-Evaluation von
&&und||fuer sichere Checks nutzen
Im naechsten Kapitel: Funktionen und ihr Scope in C.