Übungsaufgaben
Zehn Übungen zu Zeigern, Dereferenzieren und Zeigerparametern — von AFB I bis AFB III. Jede Übung gibt dir sofort Rückmeldung; wenn du nicht weiterkommst, helfen die gestuften Tipps.
Gegeben sind int t = 21; und ein Zeiger q. Ordne jeder Zeile zu, was sie bewirkt.
*q = 30; und q = &t; verwechseln. Steht der Stern links vom =, wird durch den Zeiger geschrieben — die Adresse in q bleibt gleich. Und &q ist nicht die Adresse von t, sondern die Stelle, an der q selbst im Speicher liegt.Fünf Behauptungen zu int x = 4; int *p = &x;. Nenne jeweils, ob sie stimmt.
p ist die Adresse, *p ist der Wert dort. Wer *p = 9; für eine Adressänderung hält, verwechselt genau diese beiden.p) oder um den Wert (*p) geht.double * erwartet an der Adresse 8 Byte Kommazahl — bei einem int liegt dort aber etwas anderes.int k = 4; int *z = &k; *z = *z * 3; k = k + 1; printf("%d\n", *z);
Gib die Ausgabe an.
*z = *z * 3; macht aus k den Wert 12, danach erhöht k = k + 1; auf 13. Weil z immer noch auf k zeigt, liefert *z ebenfalls 13. Typischer Fehler: 12 — als ob *z eine Kopie von k wäre, die die spätere Änderung nicht mitbekommt.*z und k sind zwei Namen für dieselbe Speicherstelle.int m = 2, n = 8; // Zeile 1 int *p = &m; // Zeile 2 *p = *p + n; // Zeile 3 p = &n; // Zeile 4 *p = *p - m; // Zeile 5 m = *p * 2; // Zeile 6
Stelle den Ablauf als Tracetabelle dar. In der letzten Spalte trägst du den Namen der Variablen ein, auf die p zeigt (m oder n).
| nach | m | n | p zeigt auf |
|---|---|---|---|
| Zeile 2 | 2 | 8 | m |
| Zeile 3 | |||
| Zeile 4 | |||
| Zeile 5 | |||
| Zeile 6 |
p auf n: Zeile 5 rechnet also n = 8 − 10 = −2, und Zeile 6 setzt m = −2 · 2 = −4. Typischer Fehler: In Zeile 5 weiter mit m rechnen, weil p „am Anfang auf m zeigte“ — ein Zeiger zeigt immer auf die Variable der letzten Zuweisung an p.p gerade zeigt, und ersetze dann *p durch diese Variable.m = m + n;, Zeile 5 heißt n = n - m;.Eine Funktion soll von zwei Zahlen die kleinere und die größere liefern. Mit return geht nur ein Wert zurück — deshalb bekommt sie zwei Zeiger. Ergänze die Lücken.
void minmax(int a, int b, , int *gr) { if (a < b) { } else { *kl = b; *gr = a; } } int main(void) { int k, g; minmax(17, 9, ); printf("%d %d\n", k, g); // Ausgabe: 9 17 return 0; }
*kl und *gr direkt in die Variablen k und g von main. Häufigster Fehler: beim Aufruf minmax(17, 9, k, g) — dann bekäme die Funktion nur die (zufälligen) Werte von k und g statt ihrer Adressen. int &kl gibt es erst in C++.int *.*kl = … geschrieben, beim Aufruf wird mit & die Adresse übergeben.Alle Zeilen stehen in main hinter int x = 1; und int *p = &x;; übersetzt wird mit gcc -Wall. Untersuche jede Zeile und lege sie in den passenden Korb.
p = x; und *p = &x; meldet gcc „makes pointer from integer“ bzw. „makes integer from pointer“: Adresse und Zahl werden vermischt. Die NULL-Zeilen übersetzt gcc ohne Meldung — der Fehler zeigt sich erst beim Ausführen als Segmentation fault. Typischer Fehler: zu glauben, der Compiler finde jeden Zeigerfehler.p ist int *, *p und x sind int, &x ist int *.Die Funktion bekommt einen Zeiger und einen gewöhnlichen int-Parameter — genau wie Parameter aus Kapitel 2.1.4 ist d eine Kopie.
void schritt(int *s, int d) { *s = *s + d; d = 0; } int main(void) { int pos = 3, w = 5; schritt(&pos, w); // Aufruf 1 schritt(&w, pos); // Aufruf 2 schritt(&pos, -w); // Aufruf 3 printf("%d %d\n", pos, w); return 0; }
Wende den Code Aufruf für Aufruf an.
-
posnach Aufruf 1 -
wnach Aufruf 1 -
wnach Aufruf 2 -
posnach Aufruf 3
d = 0; setzt lediglich die Kopie zurück — deshalb bleibt w nach Aufruf 1 bei 5. Typischer Fehler: nach Aufruf 1 für w 0 eintragen. Ausgabe am Ende: -5 13.& übergeben wird — nur die kann sich ändern.rotiere soll drei Werte im Kreis verschieben: a bekommt den Wert von b, b den von c und c den alten Wert von a. Erwartete Ausgabe: 2 3 1. Überprüfe den Code — drei Zeilen sind fehlerhaft.
c = alt;: Es ändert nur die Parameter-Kopie des Zeigers. Die Zeilen 3 und 4 sind richtig, weil dort auf beiden Seiten dereferenziert wird.int *) oder ein Wert (int) — und passt das zur anderen Seite?rotiere liest falsch, eine schreibt falsch, und der Aufruf in main übergibt das Falsche.int x = 6; int* p, q;
Tim sagt: „Wegen int* vorne sind p und q beide Zeiger.“ Beurteile die Aussagen und markiere alle zutreffenden.
int* p, q; bedeutet int *p; int q;. Wo das Leerzeichen steht, ist egal. Deshalb schreiben viele den Stern direkt an den Namen — dann fällt ein fehlender zweiter Stern sofort auf.Die Funktion teile soll für z und n den ganzzahligen Quotienten und den Rest über zwei Zeiger zurückgeben; main ruft sie für 47 und 6 auf und gibt 47 = 7 * 6 + 5 aus. Der Rest wird dabei ohne % aus dem Quotienten berechnet. Entwirf das Programm, indem du die Zeilen ordnest.
*r = z - *q * n; braucht den schon geschriebenen Quotienten, muss also nach *q = z / n; stehen. Und teile muss vor main definiert sein, weil es keinen Prototyp gibt. 47 / 6 = 7 (Ganzzahldivision), 47 − 7 · 6 = 5.main stehen.main gilt: erst deklarieren, dann aufrufen, dann ausgeben.