Programmieren mit C


Inhalt


Willkommen

Installation

Das Terminal

Exkurs: Scanf und Sonderzeichen

Exkurs: continue & break

Statische Arrays

Exkurs: sizeof

Dynamische Arrays

Exkurs: Speicherbereiche

Funktionen

Exkurs: Funktionen & Arrays

Kommandozeilenparameter

Structs

Dateien

Anwendung: Textdatei einlesen

Hintergrund: Unicode

Stringbibliothek

Ausblick

Dark Mode

Speicherbereiche

In der Vorlesung haben wir uns mit dynamischen Arrays beschäftigt. Am Ende haben wir uns die beiden Speicherbereiche - Stack und Heap - angeschaut, die uns das Betriebssystem zur Verfügung stellt. Der Stack ist ein vom Betriebssystem verwalteter Speicherbereich. Alle Variablen und statischen Arrays befinden sich hier. Der Heap wird nicht automatisch verwaltet und bietet Platz für dynamische Speicherstrukturen, unsere dynamischen Arrays.

Die unterschiedlichen Speicherbereiche können sehr abstrakt wirken. Schauen wir uns ein Beispiel an.

#include <stdio.h>

int main() {
    double arr[2000000];
    int length = sizeof(arr)/sizeof(double);

    printf("%d\n", length);
}

In diesem Beispiel wollen wir ein statisches Array mit 2 000 000 Einträgen anlegen - für numerische Simulationen eine übliche Größe. Führen wir das Programm aus, bekommen wir den folgenden Output.

Speicherzugriffsfehler

Beim Anlegen des Speichers ist etwas schief gelaufen. Die Größe des Stack reicht hier nicht mehr aus, um das Array zu speichern. Die Größe des Stacks ist betriebssystemabhängig und kann mit ulimit -s auf Unix-Systemen überprüft werden.

mia@surface-mia:~$ ulimit -s
8192

Ich habe also 8 MiB Speicher im Stack. Unser Array benötigt aber 2000000 x 8 Byte ~ 15 MiB Speicher. Die einfachste Lösung: legen wir das Array im Heap an.

#include <stdio.h>
#include <stdlib.h>

int main() {
    int length = 2000000;
    double *arr = malloc(length*sizeof(double));

    printf("%d\n", length);
}

Hier müssen daran denken, die Standardbibliothek stdlib.h einzubinden, um Zugang zur malloc()-Funktion zu erhalten.

Ab jetzt sind wir allerdings für den reservierten Speicher verantwortlich. Die üblichen Regeln mit Scopes gelten für den Speicher nicht mehr. Sobald wir das Array also nicht mehr brauchen, geben wir den Bereich wieder frei.

#include <stdio.h>
#include <stdlib.h>

int main() {
    int length = 2000000;
    double *arr = malloc(length*sizeof(double));

    printf("%d\n", length);

    free(arr);
}

Vorsicht: Der Pointer arr unterliegt weiterhin den üblichen Scope Regelungen.

if(1) {
    double *arr = malloc(length*sizeof(double));
}

printf(“%lf\n”, arr[1]); Hier kennt das Programm also weiterhin arr nach dem Scope der if-Abfrage nicht mehr. Die 15 MiB Speicher sind allerdings weiterhin reserviert, ohne dass wir Zugang dazu haben.

Um eure Computer müsst ihr euch aber keine Sorgen machen. Sobald das Programm beendet ist, wird der reservierte Speicher vom Betriebssystem freigegeben.