Aufgabenblock — AFB II
Zehn Aufgaben zum Anwenden: Code Schritt für Schritt verfolgen, Fehler finden, fehlende Werte ergänzen. Nutze die gestuften Tipps erst, wenn du wirklich festhängst — und schreib die Tracetabellen auf Papier mit, wie in der Arbeit.
int n = 6; int schritte = 0; while (n != 1) { if (n % 2 == 0) { n = n / 2; } else { n = 3 * n + 1; } schritte++; } printf("%d\n", schritte);
Stelle den Ablauf als Tracetabelle mit den Spalten n und schritte dar. Welcher Wert wird ausgegeben?
n != 1 den aktuellen Wert von n auf.Vollständige Lösung
| schritte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| n | 6 | 3 | 10 | 5 | 16 | 8 | 4 | 2 | 1 |
Bei n = 1 ist die Bedingung n != 1 falsch, die Schleife endet. → Ausgabe 8
int werte[4] = {18, 21, 19, 23}; int summe = 0; for (int i = 0; i < 4; i++) { summe += werte[i]; } double mittel = summe / 4; printf("%.2f\n", mittel);
Die Wetter-AG will die mittlere Temperatur von vier Messungen ausgeben. Erkläre, warum das Programm einen falschen Wert anzeigt. Gib den ausgegebenen und den richtigen Mittelwert an.
summe und 4? Welche Division rechnet C dann?81 / 4 wird als Ganzzahldivision gerechnet, bevor das Ergebnis in double gespeichert wird.20.00; richtig ist 81 / 4 = 20,25.Vollständige Lösung
18 + 21 + 19 + 23 = 81. Weil summe und 4 beide int sind, rechnet 81 / 4 ganzzahlig = 20. Erst danach wird 20 in mittel umgewandelt — die Nachkommastellen sind schon verloren. Ausgabe: 20.00.
Korrektur mit Cast vor der Division:
double mittel = (double) summe / 4;
Ausgabe 20.25
1#include <stdio.h> 2 3double durchschnitt(int a, int b) { 4 return (a + b) / 2; 5} 6 7int main(void) { 8 printf("%.1f\n", durchschnitt(7, 8)); 9 return 0; 10}
Die Funktion soll den Durchschnitt zweier ganzer Zahlen liefern. Überprüfe das Programm: Welche Zahl gibt es aus, und in welcher Zeile steckt der Fehler?
double, aber rechne nach, welche Typen in Zeile 4 zusammentreffen.(7 + 8) / 2 = 15 / 2 — beide Operanden sind int.7.0; Zeile 4.Vollständige Lösung
(a + b) / 2 rechnet mit zwei int-Werten: 15 / 2 = 7. Erst beim return wird 7 in 7.0 umgewandelt. Der Rückgabetyp double allein rettet nichts.
Fehler in Zeile 4. Richtig: return (a + b) / 2.0; oder return (double) (a + b) / 2; → Ausgabe 7.5.
double w[5]; printf("%zu\n", sizeof(w)); printf("%p\n", (void *) &w[0]); printf("%p\n", (void *) &w[3]);
Eine Ausführung liefert für die zweite Zeile 0x7ffc3a51e2c0. Nimm die typische Größe 8 Byte für double an. Ermittle den Wert der ersten Ausgabezeile und den Abstand in Byte zwischen den Adressen in Zeile 2 und 3.
w[3] ist das vierte Element. Davor liegen w[0], w[1], w[2].Vollständige Lösung
sizeof(w) = 5 · 8 Byte = 40.
Zwischen &w[0] und &w[3] liegen die drei Elemente w[0], w[1], w[2]: 3 · 8 Byte = 24 Byte. Die dritte Zeile lautet also 0x7ffc3a51e2d8 (hex: c0 + 18 = d8). Bei jedem Start können die Adressen anders sein — der Abstand bleibt gleich.
#include <stdio.h> void aendere(int *p, int q) { *p = *p + 10; q = q + 10; } int main(void) { int a = 1, b = 2; aendere(&a, b); printf("%d %d\n", a, b); return 0; }
Untersuche, welche der beiden Variablen die Funktion wirklich verändert. Gib die Ausgabe an.
*p = *p + 10 schreibt an die Adresse von a. q ist eine Kopie von b.a wird 11, b bleibt 2.Vollständige Lösung
| Variable | vor dem Aufruf | in aendere | nach dem Aufruf |
|---|---|---|---|
a | 1 | *p → 11 | 11 |
b | 2 | q → 12 (Kopie) | 2 |
11 2
Genau deshalb braucht scanf die Adresse &x: Nur über einen Zeiger kann eine Funktion eine Variable des Aufrufers ändern.
char ort[] = "Wetterstation"; int n = 0; for (int i = 0; ort[i] != '\0'; i++) { if (ort[i] == 't') { n++; } } printf("%d\n", n);
Werte die Schleife aus: Welche Zahl wird ausgegeben? Wie viele Byte belegt das Array ort?
'\0' trifft.Vollständige Lösung
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Zeichen | W | e | t | t | e | r | s | t | a | t | i | o | n | \0 |
Vier Treffer → Ausgabe 4. Das Array fasst 13 Zeichen und das Endezeichen → 14 Byte. Großes „T“ würde übrigens nicht mitgezählt: C unterscheidet Groß- und Kleinbuchstaben.
void setup() { pinMode(2, INPUT_PULLUP); pinMode(8, OUTPUT); } void loop() { if (digitalRead(2) == LOW) { digitalWrite(8, HIGH); delay(100); digitalWrite(8, LOW); delay(150); } else { digitalWrite(8, LOW); } }
Der Taster an Pin 2 ist ohne Widerstand direkt gegen GND angeschlossen. Erläutere das Verhalten des Sketches. Wie oft blinkt die LED, wenn der Taster 6 s lang gedrückt gehalten wird, und mit welcher Frequenz?
INPUT_PULLUP liest der Pin HIGH, solange nichts gedrückt ist. Gedrückt verbindet der Taster mit GND.loop()-Durchlauf genau eine Periode: 100 ms an + 150 ms aus.Vollständige Lösung
Gedrückt liefert digitalRead(2) den Wert LOW, also läuft der if-Zweig: Eine Periode dauert T = 100 ms + 150 ms = 250 ms = 0,25 s.
f = 1 / T = 1 / 0,25 s = 4 Hz; in 6 s: 6 · 4 = 24-mal. Losgelassen ist der Pin HIGH, der else-Zweig hält die LED aus.
#include <iostream> using namespace std; void punkteDazu(int &konto, int bonus) { konto += bonus; bonus = 0; } int main() { int stand = 40, extra = 15; punkteDazu(stand, extra); punkteDazu(stand, extra); cout << stand << " " << extra << endl; return 0; }
Vergleiche die beiden Parameter von punkteDazu: Welche Werte haben stand und extra am Ende?
& in der Parameterliste: int &konto ist eine Referenz, int bonus eine Kopie.stand. bonus = 0 ändert nur die Kopie.extra bleibt 15.Vollständige Lösung
konto ist ein zweiter Name für stand: Jeder Aufruf erhöht stand um 15 → 55 → 70.
bonus ist eine Kopie von extra. bonus = 0 setzt nur die Kopie zurück; extra bleibt 15. Auch beim zweiten Aufruf wird deshalb wieder 15 übergeben.
70 15
class Konto { private: int stand; public: Konto(int start) { stand = start; } void einzahlen(int b) { if (b > 0) stand += b; } bool abheben(int b) { if (b > stand) return false; stand -= b; return true; } int getStand() { return stand; } }; int main() { Konto k(50); k.einzahlen(30); k.abheben(100); k.einzahlen(-20); k.abheben(45); cout << k.getStand() << endl; return 0; }
Analysiere die Methodenaufrufe in main. Welcher Kontostand wird ausgegeben? Wie viele der Aufrufe verändern den Kontostand nicht?
abheben(100) bei Stand 80 und einzahlen(-20) scheitern an ihren if-Bedingungen.Vollständige Lösung
| Aufruf | Bedingung | stand |
|---|---|---|
Konto k(50) | Konstruktor | 50 |
einzahlen(30) | 30 > 0 ✓ | 80 |
abheben(100) | 100 > 80 → false | 80 |
einzahlen(-20) | −20 > 0 ✗ | 80 |
abheben(45) | 45 > 80 ✗ → abheben | 35 |
→ Ausgabe 35, zwei wirkungslose Aufrufe. Weil stand private ist, kann main den Stand nur über die Methoden ändern — so bleiben ungültige Werte draußen (Kapselung).
Für ein Würfelspiel mit einem Spezialwürfel braucht ihr ganze Zufallszahlen von 5 bis 12 (beide einschließlich). Die Anweisung hat die Form int z = a + rand() % n;
Leite her, welche Zahl für n einzusetzen ist. Wie viele Tipps braucht man beim Zahlenraten im Bereich 1 bis 500 höchstens, wenn man immer die Mitte des verbleibenden Bereichs tippt?
rand() % n liefert 0 bis n − 1. Welcher Wert kommt heraus, wenn man a addiert?Vollständige Lösung
rand() % n liefert 0 … n − 1, also 5 + rand() % n die Werte 5 … 5 + n − 1.
5 + n − 1 = 12 ⇔ n = 12 − 5 + 1 = 8 → int z = 5 + rand() % 8;
Jeder Tipp halbiert den Bereich. Mit k Tipps findet man die Zahl sicher, wenn 2k ≥ 500: 28 = 256 reicht nicht, 29 = 512 reicht → höchstens 9 Tipps.
