Hier sind die 12 häufigsten Fehler beim Programmieren in C und C++ — vom vergessenen Semikolon bis zum falsch abgefragten Taster. Zu jedem Fehler siehst du den falschen und den richtigen Code, die Erklärung und einen Merksatz. Wer einen Fehler kennt, macht ihn seltener.
Die 12 häufigsten Fehler
1Semikolon vergessen — Fehler in der falschen Zeile gesucht
int zahl = 5 printf("%d\n", zahl);
int zahl = 5; printf("%d\n", zahl);
So wird es oft gemacht: Nach int zahl = 5 fehlt das Semikolon. gcc meldet error: expected ',' or ';' before 'printf' — und es wird in der printf-Zeile gesucht.
Warum falsch: Der Compiler merkt das fehlende ; erst, wenn das nächste Wort kommt. Die Meldung zeigt deshalb auf die Zeile danach.
Richtig ist: Bei „expected ;“ immer auch das Ende der Zeile davor prüfen und die erste Meldung zuerst beheben.
Jede Anweisung endet mit einem Semikolon.
2Ganzzahldivision übersehen
int richtig = 7, gesamt = 8; double quote = richtig / gesamt; printf("%.3f\n", quote);
double quote = (double) richtig / gesamt;
So wird es oft gemacht: Die Trefferquote soll 7 / 8 = 0,875 sein. Das Programm gibt 0.000 aus.
Warum falsch: Beide Operanden sind int, also rechnet 7 / 8 ganzzahlig und liefert 0. Dass das Ergebnis danach in einem double landet, ändert daran nichts mehr.
Richtig ist: Einen Operanden vor der Division umwandeln: (double) richtig / gesamt → 0.875.
int / int bleibt int — erst casten, dann teilen.
3Falscher Platzhalter in printf
double preis = 2.5; printf("%d\n", preis);
double preis = 2.5; printf("%.2f\n", preis);
So wird es oft gemacht: printf("%d", preis) mit double preis — ausgegeben wird eine sinnlose Zahl.
Warum falsch: %d erwartet ein int. printf prüft die Typen nicht, sondern liest die Bytes falsch aus. gcc warnt mit -Wall: format '%d' expects argument of type 'int', but argument 2 has type 'double'.
Richtig ist: %d für int, %f bzw. %.2f für double, %c für char, %s für Zeichenketten.
Der Platzhalter muss zum Typ passen.
4Zuweisung statt Vergleich in der Bedingung
int versuche = 5; if (versuche = 3) { printf("drei\n"); }
if (versuche == 3) { printf("drei\n"); }
So wird es oft gemacht: if (versuche = 3) — obwohl versuche 5 ist, wird „drei“ ausgegeben.
Warum falsch: = weist 3 zu; der Wert des Ausdrucks ist 3, und alles außer 0 gilt in C als wahr. Die Bedingung ist also immer erfüllt — und versuche ist danach auch noch verändert.
Richtig ist: == zum Vergleichen. -Wall warnt: suggest parentheses around assignment used as truth value.
Ein = weist zu, zwei == vergleichen.
5Erwarten, dass eine Funktion den Parameter ändert
void erhoehe(int x) { x = x + 1; } int main(void) { int leben = 3; erhoehe(leben); printf("%d\n", leben); return 0; }
void erhoehe(int *x) { *x = *x + 1; } // Aufruf: erhoehe(&leben); → 4
So wird es oft gemacht: erhoehe(leben) soll ein Leben dazugeben — ausgegeben wird weiter 3.
Warum falsch: Beim Aufruf wird der Wert von leben in x kopiert. x = x + 1 ändert nur die Kopie, die am Funktionsende verschwindet.
Richtig ist: Entweder das Ergebnis mit return zurückgeben (leben = erhoehe(leben);) oder die Adresse übergeben: erhoehe(&leben) mit int *x → 4.
Eine Funktion bekommt Kopien — ändern kann sie nur über eine Adresse.
6Bei scanf das & vergessen
int alter; scanf("%d", alter);
int alter; scanf("%d", &alter);
So wird es oft gemacht: scanf("%d", alter); — das Programm stürzt beim Einlesen ab oder liest nichts ein.
Warum falsch: scanf muss in die Variable schreiben, braucht also ihre Adresse. Ohne & wird der (zufällige) Inhalt von alter als Adresse benutzt. gcc warnt: expects argument of type 'int *'.
Richtig ist: scanf("%d", &alter); — Ausnahme: Bei einem char-Array für %s ist der Name schon eine Adresse.
scanf braucht die Adresse: &variable.
7Zeiger und Wert verwechselt
int temp = 18; int *p = &temp; p = 21;
int temp = 18; int *p = &temp; *p = 21; // temp ist jetzt 21
So wird es oft gemacht: Über den Zeiger soll die Temperatur auf 21 gesetzt werden: p = 21;.
Warum falsch: p ist die Adresse. p = 21 lässt den Zeiger auf die Speicherstelle 21 zeigen — temp bleibt 18. gcc warnt makes pointer from integer without a cast (neuere Versionen: Fehler).
Richtig ist: *p = 21; schreibt an die Adresse, auf die p zeigt → temp ist 21.
p ist die Adresse, *p ist der Wert dort.
8Array bei 1 beginnen oder bis n zählen
int noten[5] = {2, 3, 1, 2, 4}; for (int i = 1; i <= 5; i++) { printf("%d ", noten[i]); }
for (int i = 0; i < 5; i++) { printf("%d ", noten[i]); }
So wird es oft gemacht: Fünf Noten werden mit for (int i = 1; i <= 5; i++) ausgegeben: Die erste Note fehlt, am Ende erscheint eine fremde Zahl.
Warum falsch: Die Indizes eines Arrays mit 5 Elementen sind 0 bis 4. noten[5] liegt hinter dem Array. C prüft das nicht — undefiniertes Verhalten, kein Fehler beim Übersetzen.
Richtig ist: for (int i = 0; i < 5; i++) — Start bei 0, Bedingung mit < und der Anzahl.
Index von 0 bis n − 1: i = 0; i < n.
9Kein Platz für das Endezeichen
char kurz[4]; strcpy(kurz, "Mensa");
char kurz[6]; // 5 Zeichen + '\0' strcpy(kurz, "Mensa");
So wird es oft gemacht: char kurz[4]; und dann strcpy(kurz, "Mensa");.
Warum falsch: „Mensa“ braucht 5 Zeichen plus '\0', also 6 Byte. strcpy schreibt 2 Byte über das Array hinaus und überschreibt fremden Speicher. gcc meldet: writing 6 bytes into a region of size 4.
Richtig ist: Array mindestens strlen + 1 groß anlegen: char kurz[6]; — oder mit char kurz[] = "Mensa"; die Größe automatisch bestimmen lassen.
Eine Zeichenkette braucht ein Byte mehr als Buchstaben.
10Zeichenketten mit == vergleichen
char antwort[10]; scanf("%9s", antwort); if (antwort == "ja") { … }
if (strcmp(antwort, "ja") == 0) { … }
So wird es oft gemacht: Der Vokabeltrainer prüft if (antwort == "ja") — auch bei der Eingabe „ja“ ist die Bedingung falsch.
Warum falsch: Ein Array-Name steht für die Adresse des ersten Zeichens. == vergleicht also zwei Adressen, nicht die Buchstaben — die sind nie gleich.
Richtig ist: strcmp(antwort, "ja") == 0 aus <string.h>. In C++ mit std::string darf man == benutzen.
C-Strings vergleicht strcmp, nicht ==.
11Taster mit INPUT_PULLUP falsch herum abgefragt
pinMode(4, INPUT_PULLUP); … if (digitalRead(4) == HIGH) { // „gedrückt?“ digitalWrite(7, HIGH); // Pumpe an }
if (digitalRead(4) == LOW) { // gedrückt = LOW digitalWrite(7, HIGH); }
So wird es oft gemacht: Pflanzenbewässerung: Die Pumpe läuft, solange der Taster nicht gedrückt ist, und stoppt beim Drücken.
Warum falsch: Mit INPUT_PULLUP zieht ein eingebauter Widerstand den Pin auf HIGH. Der gedrückte Taster verbindet ihn mit GND → LOW. Die Logik ist also umgekehrt.
Richtig ist: Gedrückt heißt digitalRead(4) == LOW.
INPUT_PULLUP: gedrückt = LOW.
12srand bei jedem Wurf neu aufgerufen
for (int i = 0; i < 3; i++) { srand(time(0)); printf("%d ", rand() % 6 + 1); }
srand(time(0)); // einmal, vor der Schleife for (int i = 0; i < 3; i++) { printf("%d ", rand() % 6 + 1); }
So wird es oft gemacht: Ein Würfelprogramm ruft vor jedem Wurf srand(time(0)) auf — alle drei Würfe zeigen dieselbe Zahl.
Warum falsch: time(0) ändert sich nur einmal pro Sekunde. Innerhalb derselben Sekunde startet srand die Zufallsfolge immer wieder am selben Punkt, rand() liefert also jedes Mal dieselbe erste Zahl.
Richtig ist: srand(time(0)); genau einmal am Programmanfang, danach beliebig oft rand().
srand einmal, rand beliebig oft.
