Zeiger und Speicher

Dynamische Speicherverwaltung in C und C++

In dieser Lektion reservierst du ein Array, dessen Größe erst zur Laufzeit feststeht, und gibst diesen Speicher sicher wieder frei.

Einführung

Dynamischer Speicher wird verwendet, wenn Größe oder Lebensdauer der Daten beim Kompilieren noch nicht feststehen, etwa wenn die Elementanzahl von der Eingabe des Benutzers abhängt. Dieser Speicher wird während der Programmausführung reserviert und muss wieder freigegeben werden, wenn er nicht mehr gebraucht wird.

Wichtige Punkte

  • Ein Zeiger darf nur auf ein noch existierendes Objekt des richtigen Typs zeigen oder null sein.
  • Jeder reservierte Speicherbereich muss genau einmal freigegeben werden.
  • Mache deutlich, welche Funktion den Speicher besitzt (ownership) und welche Daten nur gelesen werden (const).

Codebeispiele in C und C++

C
Code ausführen →
main.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    size_t count = 5;
    int *values = calloc(count, sizeof *values);
    if (!values) return 1;
    for (size_t i = 0; i < count; ++i) values[i] = (int)(i * i);
    printf("last=%d\n", values[count - 1]);
    free(values);
    return 0;
}
Ergebnis der Ausführung
last=16
C++
Code ausführen →
main.cpp
#include <iostream>
#include <vector>

int main() {
    std::vector<int> values(5);
    for (std::size_t i = 0; i < values.size(); ++i) values[i] = static_cast<int>(i * i);
    std::cout << "last=" << values.back() << '\n';
}
Ergebnis der Ausführung
last=16

C und C++ im Vergleich

In C reserviert calloc Speicher für 5 ganze Zahlen und initialisiert sie mit 0. Das Programm muss prüfen, ob die Reservierung fehlgeschlagen ist, und am Ende free aufrufen, sonst entsteht ein Speicherleck (memory leak). In C++ verwaltet std::vector seinen Speicher selbst und gibt ihn automatisch frei, wenn er nicht mehr verwendet wird, selbst wenn eine Ausnahme auftritt.

C

Besitz und Freigabe von Speicher muss der Programmierer vollständig selbst sicherstellen.

C++

Container und RAII geben Ressourcen automatisch frei, wenn die Lebensdauer des Objekts endet.

Übungen zur Vertiefung

Führe beide Versionen aus und ändere dann den Code, um zu beobachten, welche Sicherheit jede Sprache bietet.

  • Teste mit Nullzeigern und fehlgeschlagener Speicherreservierung.
  • Führe das Programm mit AddressSanitizer und UndefinedBehaviorSanitizer aus, um Speicherfehler zu finden.
  • Notiere klar, welcher Zeiger den Speicher besitzt und welcher nur zum Lesen dient.

Mit einer Challenge üben

Nutze den Inhalt dieser Lektion, um ein echtes Problem zu lösen. Jede Challenge läuft im Browser, mit sofortigen Tests und einem KI-Review.

Alle Challenges