// ============================================ // Checkpoint A: Memory & Datentypen // Lösung für Selbsttest nach Modul 1-2 // ============================================ #include #include #include #include // ============================================ // AUFGABE 1: Stack vs Heap Analyse // ============================================ void aufgabe1_memory_analyse() { printf("=== AUFGABE 1: Memory-Analyse ===\n\n"); // Gegeben: Was passiert hier? printf("Code:\n"); printf("void test() {\n"); printf(" int x = 42; // Stack\n"); printf(" int *p = &x; // Stack (Pointer)\n"); printf(" int *heap = malloc(4); // Heap\n"); printf(" *heap = 100;\n"); printf("} // <- Was wird freigegeben?\n\n"); // Lösung: printf("LÖSUNG:\n"); printf("1. x (int, Wert 42) -> Stack -> AUTOMATISCH freigegeben\n"); printf("2. p (Pointer auf x) -> Stack -> AUTOMATISCH freigegeben\n"); printf("3. heap (Pointer-Wert) -> Stack -> AUTOMATISCH freigegeben\n"); printf("4. *heap (int, Wert 100) -> Heap -> NICHT freigegeben! MEMORY LEAK!\n\n"); printf("Fehler: Kein free(heap) vorhanden!\n\n"); } // ============================================ // AUFGABE 2: Typ-Grenzen und Overflow // ============================================ void aufgabe2_typ_grenzen() { printf("=== AUFGABE 2: Typ-Grenzen ===\n\n"); printf("Frage: Was ist der Output?\n"); printf("short s = 32767;\n"); printf("s = s + 1;\n"); printf("printf(\"%%d\\n\", s);\n\n"); // Demonstrieren short s = 32767; printf("Vor: s = %d\n", s); s = s + 1; printf("Nach: s = %d\n\n", s); printf("LÖSUNG: -32768 (Overflow bei signed short!)\n"); printf("32767 ist SHRT_MAX, +1 ergibt -32768 (SHRT_MIN)\n"); printf("Bei signed integer overflow ist Verhalten undefiniert!\n\n"); } // ============================================ // AUFGABE 3: Pointer-Dereferenzierung // ============================================ void aufgabe3_pointer() { printf("=== AUFGABE 3: Pointer ===\n\n"); printf("Frage: Was ist der Output?\n"); printf("int a = 5, b = 10;\n"); printf("int *p1 = &a, *p2 = &b;\n"); printf("p1 = p2;\n"); printf("*p1 = 20;\n"); printf("printf(\"%%d %%d\\n\", a, b);\n\n"); // Demonstrieren int a = 5, b = 10; int *p1 = &a, *p2 = &b; p1 = p2; // p1 zeigt jetzt auch auf b! *p1 = 20; // b wird 20! printf("Output: %d %d\n\n", a, b); printf("LÖSUNG: 5 20\n"); printf("- a bleibt 5 (unverändert)\n"); printf("- p1 zeigt nach p1=p2 auf b\n"); printf("- *p1 = 20 ändert b auf 20\n"); printf("- a wurde nie verändert!\n\n"); } // ============================================ // AUFGABE 4: Memory-Layout Visualisierung // ============================================ void aufgabe4_memory_layout() { printf("=== AUFGABE 4: Memory-Layout ===\n\n"); printf("Aufgabe: Zeichne das Memory-Layout für:\n"); printf("void foo() {\n"); printf(" int x = 10; // Line 1\n"); printf(" int *p = malloc(4); // Line 2\n"); printf(" *p = 20; // Line 3\n"); printf(" int arr[3] = {1,2,3}; // Line 4\n"); printf("}\n\n"); printf("LÖSUNG (nach Line 4):\n"); printf("┌─────────────────┐\n"); printf("│ Stack │\n"); printf("│ ┌───────────┐ │\n"); printf("│ │ x = 10 │ │ <- int (4 Bytes)\n"); printf("│ ├───────────┤ │\n"); printf("│ │ p = 0x... │ │ <- Pointer (8 Bytes auf 64-bit)\n"); printf("│ │ (zeigt │ │\n"); printf("│ │ auf Heap)│ │\n"); printf("│ ├───────────┤ │\n"); printf("│ │ arr[0]=1 │ │ <- Array (12 Bytes = 3*4)\n"); printf("│ │ arr[1]=2 │ │\n"); printf("│ │ arr[2]=3 │ │\n"); printf("│ └───────────┘ │\n"); printf("└─────────────────┘\n"); printf(" │\n"); printf(" ▼\n"); printf("┌─────────────────┐\n"); printf("│ Heap │\n"); printf("│ ┌───────────┐ │\n"); printf("│ │ *p = 20 │ │ <- malloc(4)\n"); printf("│ └───────────┘ │\n"); printf("└─────────────────┘\n\n"); printf("Nach foo() Ende:\n"); printf("- Stack: Alles freigegeben (x, p, arr)\n"); printf("- Heap: *p BLEIBT (Memory Leak ohne free!)\n\n"); } // ============================================ // BONUS: Typ-Sicherheit mit Fixed-Width // ============================================ void bonus_fixed_width() { printf("=== BONUS: Fixed-Width Typen ===\n\n"); printf("Vorteile von stdint.h:\n\n"); printf("Statt 'int' (Größe variiert):\n"); printf(" int32_t x; // Garantiert 32-bit\n"); printf(" int64_t y; // Garantiert 64-bit\n"); printf(" uint8_t z; // Garantiert 8-bit, unsigned\n\n"); printf("Präfixe:\n"); printf(" int = signed\n"); printf(" uint = unsigned\n"); printf(" 8/16/32/64 = Bits\n\n"); printf("Beispiel Portabilität:\n"); int32_t portabel = 100; // Überall 32-bit printf(" int32_t: %zu Bytes (immer 4)\n", sizeof(portabel)); printf(" int: %zu Bytes (kann 2, 4 oder 8 sein)\n\n", sizeof(int)); } // ============================================ // HAUPTPROGRAMM // ============================================ int main() { printf("╔══════════════════════════════════════════════════════════╗\n"); printf("║ CHECKPOINT A: LÖSUNGEN (Memory & Datentypen) ║\n"); printf("╚══════════════════════════════════════════════════════════╝\n\n"); printf("Diese Datei enthält die Lösungen für Checkpoint A.\n"); printf("Vergleiche mit deinen Antworten!\n\n"); aufgabe1_memory_analyse(); aufgabe2_typ_grenzen(); aufgabe3_pointer(); aufgabe4_memory_layout(); bonus_fixed_width(); printf("╔══════════════════════════════════════════════════════════╗\n"); printf("║ ZUSAMMENFASSUNG ║\n"); printf("╠══════════════════════════════════════════════════════════╣\n"); printf("║ ✓ Stack: Automatisch, schnell, begrenzt ║\n"); printf("║ ✓ Heap: Manuell, flexibel, persistent ║\n"); printf("║ ✓ malloc/free immer paaren! ║\n"); printf("║ ✓ Pointer = Adresse, * = Wert an Adresse ║\n"); printf("║ ✓ Integer-Overflow = undefiniertes Verhalten ║\n"); printf("║ ✓ Fixed-Width Typen (stdint.h) für Portabilität ║\n"); printf("╚══════════════════════════════════════════════════════════╝\n"); return 0; }