π€ 1. C-Strings & das unsichtbare Null-Byte ('\0')
In C gibt es keinen eingebauten string-Datentyp. Ein C-String ist schlicht ein sequentielles Array aus char-Bytes, das zwingend mit dem ASCII-Wert 0 ('\0', Null-Terminator) endet:
char str[] = "C++"; // Belegt im Speicher 4 Bytes: ['C', '+', '+', '\0']
Ein C-String gleicht einem GΓΌterzug. Die CPU weiΓ nicht im Voraus, wie viele Waggons (Buchstaben) angehΓ€ngt sind. Sie fΓ€hrt von Waggon zu Waggon, bis sie auf das rote Schlusssignal ('\0') stΓΆΓt. Fehlt dieses Null-Byte, fΓ€hrt die CPU ungebremst ΓΌber fremden Speicher weiter (Buffer Overread)!
π’ 2. Stack vs. Heap: Die Speicherarchitektur
Jedes C-Programm teilt seinen virtuellen Adressraum in klar definierte Segmente auf:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Hohe Adressen (0x7FFF...)
β STACK (Automatisch, LIFO, sehr schnell, z.B. 8MB Limit)β βΌ wΓ€chst nach unten
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β (Freier Raum) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β HEAP (Dynamischer Speicher, manuell mit malloc/free) β β² wΓ€chst nach oben
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β BSS / DATA (Globale & statische Variablen) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β TEXT SEGMENT (Kompilierter Maschinencode / Read-Only) β Niedrige Adressen (0x0000...)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Eigenschaft | Stack (Stapelspeicher) | Heap (Freispeicher) |
|---|---|---|
| Lebensdauer | Automatisch an Scope (Funktionsblock {}) gebunden |
Manuell: Bis free() aufgerufen wird |
| GrΓΆΓe | Fest zur Compile-Zeit / Begrenzt (Stack Overflow bei riesigen Arrays) | Dynamisch zur Laufzeit (GBs an RAM) |
| Verwaltung | CPU Stack Pointer Register (0 Overhead) | malloc() / calloc() / realloc() / free() |
π οΈ 3. Dynamische Speicherallokation & Memory Leaks
Der Lebenszyklus einer Heap-Allokation in C:
#include <stdlib.h>
// 1. Speicher auf dem Heap reservieren (z.B. fΓΌr 10 Ganzzahlen):
int* buffer = (int*)malloc(10 * sizeof(int));
if (buffer == NULL) {
// Allokation fehlgeschlagen (Out of Memory)
return -1;
}
// 2. Speicher verwenden:
buffer[0] = 123;
// 3. Speicher freigeben & Dangling Pointer eliminieren:
free(buffer);
buffer = NULL; // WICHTIG: Verhindert versehentlichen Zugriff nach Freigabe!
π§ Diagnostischer Selbst-Check
ΓberprΓΌfe dein VerstΓ€ndnis zu Speichersicherheit, Syntax und Systems-Design mit gezieltem Feedback:
π― Aufgaben & Checkliste in aufgabe.c
malloc() reserviert rohen, uninitialisierten Speicher (enthΓ€lt zufΓ€lligen Datensalat/Garbage). calloc(n, size) setzt alle Bits garantiert auf 0!