Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 16 Dynamische Speicherverwaltung
  gp 16.1 Das Speicherkonzept
  gp 16.2 Speicheralloziierung mit malloc()
  gp 16.3 Die Mysterie von NULL
    gp 16.3.1 NULL für Fortgeschrittene
    gp 16.3.2 Was jetzt – NULL, 0 oder \0 ... ?
    gp 16.3.3 Zusammengefasst
  gp 16.4 Speicherreservierung und ihre Probleme
  gp 16.5 free() – Speicher wieder freigeben
  gp 16.6 Die Freispeicherverwaltung
    gp 16.6.1 Prozessinterne Freispeicherverwaltung
  gp 16.7 Dynamisches Array
  gp 16.8 Speicher dynamisch reservieren mit realloc und calloc
  gp 16.9 Speicher vom Stack anfordern mit alloca (nicht ANSI C)
  gp 16.10 free – Speicher wieder freigeben
  gp 16.11 Zweidimensionale dynamische Arrays
  gp 16.12 Wenn die Speicheralloziierung fehlschlägt
    gp 16.12.1 Speicheranforderung reduzieren
    gp 16.12.2 Speicheranforderungen aufteilen
    gp 16.12.3 Einen Puffer konstanter Größe verwenden
    gp 16.12.4 Zwischenspeichern auf Festplatte vor der Alloziierung
    gp 16.12.5 Nur so viel Speicher anfordern wie nötig


Galileo Computing - Zum Seitenanfang

16.8 Speicher dynamisch reservieren mit realloc und calloc  toptop

In der Headerdatei <stdlib.h> sind noch zwei weitere Funktionen zum dynamischen Reservieren von Speicher deklariert. Hier die Syntax zu diesen Funktionen:

void *calloc(size_t anzahl, size_t groesse);
void *realloc(void *zgr, size_t neuegroesse);

Die Funktion calloc() ist der Funktion malloc() sehr ähnlich. Nur, dass es bei der Funktion calloc() nicht einen, sondern zwei Parameter gibt. Im Gegensatz zu malloc() können Sie mit calloc() noch die anzahl von Speicherobjekten angeben, die reserviert werden soll. Wird z.B. für 100 Objekte vom Typ int Speicherplatz benötigt, so erledigen Sie dies mit calloc() folgendermaßen:

int *zahlen;
zahlen = (int *)calloc(100,sizeof(int));

Außerdem werden mit der Funktion calloc() alle Werte des alloziierten Speicherbereichs automatisch mit dem Wert 0 initialisiert. Bei malloc() hat der reservierte Speicherplatz zu Beginn einen undefinierten Wert. Allerdings können Gleitkomma- und Zeiger-Nullen auch ganz anders dargestellt werden, weshalb man sich auf solchen Feldern nicht auf die Nullen verlassen kann. Gleichwertig zu calloc() verhält sich außerdem folgendes Code-Konstrukt mit malloc():

ptr = calloc(100, sizeof(int));
// Alternative dafür mit malloc(); erfüllt denselben Zweck
ptr = malloc(100 * sizeof(int));
memset(ptr, 0, 100 * sizeof(int));

Da calloc() außer den beiden eben genannten Unterschieden genauso funktioniert wie die Funktion malloc(), soll nicht mehr näher auf diese Funktion eingegangen werden.

Interessanter ist dagegen die dynamische Speicherreservierung mit der Funktion realloc(). Mit dieser Funktion ist es möglich, während des laufenden Programms so viel Speicher zu reservieren, wie Sie benötigen. Des Weiteren können Sie sich darauf verlassen, wenn im aktuellen Speicherblock nicht mehr genügend freier Speicher vorhanden ist, dass ein neuer Pool mit malloc() erstellt wird und die ganzen Ergebnisse herüberkopiert werden.

Mit realloc() ist es noch einfacher, z.B. dynamische Arrays zu programmieren. Die Anfangsadresse des dynamischen Arrays ist diejenige, auf die der Zeiger (zgr) zeigt. Der Parameter neuegroesse dient dazu, einen bereits zuvor alloziierten Speicherplatz auf neuegroesse Bytes zu vergrößern. Die Funktion realloc() ermöglicht es auch, den Speicherplatz zu verkleinern. Dazu wird einfach der hintere Teil des Speicherblocks freigegeben, während der vordere Teil unverändert bleibt. Bei einer Vergrößerung des Speicherplatzes mit realloc() behält der vordere Teil auf jeden Fall seinen Wert, und der neue Teil wird einfach hinten angehängt. Dieser angehängte Wert ist aber wie bei malloc() undefiniert. Hier ein kleines Beispiel, wie ein Array mit der Funktion realloc() dynamisch erstellt wird:

/* realloc1.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   int n=0, max=10, z,i;
   int *zahlen=NULL;
   /* Wir reservieren Speicher für 10 int-Werte mit calloc */
   zahlen = (int *)calloc(max, sizeof(int));
   if(NULL == zahlen) {
      printf("Kein Virtueller RAM mehr vorhanden ... !");
      return EXIT_FAILURE;
   }
   printf("Zahlen eingeben --- Beenden mit 0\n");
   /* Endlossschleife */
   while(1) {
      printf("Zahl (%d) eingeben : ", n+1);
      scanf("%d", &z);
      if(z==0)
         break;
      /* Reservierung von Speicher während der Laufzeit
       * des Programms mit realloc */
       if(n >= max) {
          max += max;
          zahlen = (int *)realloc(zahlen,max*sizeof(int));
          if(NULL == zahlen) {
             printf("Kein Virtueller RAM mehr vorhanden ... !");
             return EXIT_FAILURE;
          }
          printf("Speicherplatz reserviert "
                 " (%d Bytes)\n", sizeof(int) * max);
       }
       zahlen[n++] = z;
   }
   printf("Folgende Zahlen wurden eingegeben ->\n\n");
   for(i = 0; i < n; i++)
      printf("%d ", zahlen[i]);
   printf("\n");
   free(zahlen);
   return EXIT_SUCCESS;
}

Den benötigten Speicherbedarf könnten Sie in diesem Beispiel auch einzeln alloziieren. Die einfache Anwendung dieser Funktion soll nicht darüber hinwegtäuschen, dass auch hier erst der alte Speicherbereich temporär zwischengespeichert werden muss, so wie bei der Funktion malloc(). In diesem Fall ist es aber einfacher, da Sie sich nicht mehr selbst darum kümmern müssen.

Im Beispiel wurde der Speicherplatz nach jedem erneuten Alloziieren mit calloc() gleich verdoppelt (max += max). Dies ist nicht optimal. Benötigt ein Programm z.B. täglich 500 double-Werte, wäre es am sinnvollsten, erst nach 500 double-Werten neuen Speicher zu alloziieren. Somit müsste das Programm nur einmal am Tag neuen Speicher bereitstellen.

Dasselbe Beispiel lässt sich recht ähnlich und einfach auch auf char-Arrays umschreiben. Das folgende Listing demonstriert die dynamische Erweiterung eines Strings:

/* dyn_string1.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF 255
int main(void) {
   size_t len;
   char *str = NULL;
   char puffer[BUF];
   printf("Ein dynamisches char-Array für Strings\n");
   printf("Eingabe machen : ");
   fgets(puffer, BUF, stdin);
   str = (char *)malloc(strlen(puffer)+1);
   if(NULL == str) {
      printf("Kein Virtueller RAM mehr vorhanden ... !");
      return EXIT_FAILURE;
   }
   strcpy(str, puffer);
   printf("Weitere Eingabe oder beenden mit \"END\"\n>");
   /* Endlossschleife */
   while(1) {
      fgets(puffer, BUF, stdin);
      /* Abbruchbedingung */
      if(strcmp(puffer,"end\n")==0 || strcmp(puffer,"END\n")==0)
         break;
       /* Aktuelle Länge von str zählen für realloc */
       len = strlen(str);
       /* Neuen Speicher für str anfordern */
       str = (char *)realloc(str,strlen(puffer)+len+1);
       if(NULL == str) {
          printf("Kein Virtueller RAM mehr vorhanden ... !");
          return EXIT_FAILURE;
       }
       /* Hinten anhängen */
       strcat(str, puffer);
   }
   printf("Ihre Eingabe lautete: \n");
   printf("%s", str);
   free(str);
   return EXIT_SUCCESS;
}

Beim char-Array läuft es ähnlich ab wie schon im Beispiel mit den int-Werten zuvor. Es muss allerdings immer darauf geachtet werden, dass bei erneuter Speicheranforderung mit realloc() das Stringende-Zeichen berücksichtigt wird (+1). Ansonsten ist der Vorgang recht simpel: String einlesen, Zeichen zählen, erneut Speicher reservieren und hinten anhängen.

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de