2015-06-12 8 views
5

In diesem Programm (C, nicht C++), warum malloc immer die richtige Größe unabhängig von der Verwendung des Operators sizeof zurückgibt?Wird die Größe des Operators für malloc benötigt?

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

int main(void) { 
    char *c = malloc(3); 
    short *s = malloc(3); /* or malloc(3 * sizeof(short))? */ 
    int *i = malloc(3); /* or malloc(3 * sizeof(int))? */ 
    long *l = malloc(3); /* or malloc(3 * sizeof(long))? */ 

    printf("%p\n", c++); 
    printf("%p\n", c++); 
    printf("%p\n", c++); 

    printf("---\n"); 

    printf("%p\n", s++); 
    printf("%p\n", s++); 
    printf("%p\n", s++); 

    printf("---\n"); 

    printf("%p\n", i++); 
    printf("%p\n", i++); 
    printf("%p\n", i++); 

    printf("---\n"); 

    printf("%p\n", l++); 
    printf("%p\n", l++); 
    printf("%p\n", l++); 

    return 0; 
} 

Die Ausgabe lautet:

0x1e82010 (1 byte) 
0x1e82011 
0x1e82012 
--- 
0x1e82030 (2 bytes) 
0x1e82032 
0x1e82034 
--- 
0x1e82050 (4 bytes) 
0x1e82054 
0x1e82058 
--- 
0x1e82070 (8 bytes) 
0x1e82078 
0x1e82080 

bin ich etwas fehlt?

4.0.4-303.fc22.x86_64 Klirren Version 3.5.0 (Tags/RELEASE_350/final) Ziel: x86_64-RedHat-Linux-Gnu Thread-Modell: Posix

+0

Sie machen Adressarithmetik; Sie greifen nicht auf den Speicher zu, was ebenso gut ist, da nur 3 Bytes zugewiesen wurden, so dass Sie für alle außer dem 'char *' - Teil auf Speicher außerhalb der Grenzen zugreifen. –

+1

Was Sie tun, ist undefiniertes Verhalten. Die Tatsache, dass es "scheint" zu funktionieren, macht es nicht legal (oder gültig). Sie könnten diese Zeiger auf 'NULL' setzen und die gleichen Ergebnisse erhalten. – Cornstalks

+1

Wie haben Sie festgestellt, wie viel Speicher malloc zugewiesen hat? –

Antwort

2

Die Anzahl der Bytes erhöht Wenn Sie einen Zeiger inkrementieren, wird nur auf seinen Typ - z Wenn Sie eine int* um 1 erhöhen, erhöhen Sie die Adresse um 4 Bytes. Das hat nichts mit malloc oder sizeof oder irgendetwas zu tun.

Sie werden feststellen, dass, wenn Sie Werte in diesem Zeiger beginnen zu speichern, die Sie in seltsame Verhalten führen werden, da Sie nicht genug Platz, um 3 short s oder 3 int s oder 3 long s zugewiesen haben.

4

Das Inkrementieren eines Zeigers erhöht die gespeicherte Adresse um die Größe des Basistyps. Es hängt nicht davon ab, auf was der Zeiger zeigt.

10
long *l = malloc(3); 

Diese zuordnet (oder eher versucht zuzuteilen) 3 Bytes.

In der Regel wird malloc() tatsächlich mehr als Sie anfordern, für die Ausrichtung und Buchhaltung Zwecke. Nach dem Aufruf von malloc(3) können Sie also mit der Speicherung von 3 long Werten im zugewiesenen Speicher fortfahren. Aber es ist nicht garantiert.

Ja, Sie brauchen die sizeof.

Und der beste Weg, das schreiben ist:

long *l = malloc(3 * sizeof *l); 

Durch die Verwendung der Größe von dem, was der Zeiger auf (sizeof *l), müssen Sie den Typen nicht angeben long zweimal, und der Code gewonnen nicht brechen, wenn sich der Typ später ändert.

Noch besser:

long *l = malloc(3 * sizeof *l); 
if (l == NULL) { 
    /* malloc failed, recover or bail out */ 
} 

Wenn Sie möchten, können Sie dies schreiben als:

long *l = malloc(3 * sizeof(*l)); 

aber die zusätzlichen Klammern sind nicht erforderlich, Größe sizeof ein unärer Operator ist, keine Funktion .

Wenn Sie einen Zeiger inkrementieren, wird der Wert um die Größe des Typs erhöht, auf den er zeigt. long ist anscheinend 8 Bytes auf Ihrem System, so wird dies l um mindestens 24 Bytes weit nach den 3 Bytes, die Sie angefordert haben, von malloc. Das Ergebnis ist ein nicht definiertes Verhalten.

Und durch Inkrementieren l, haben Sie den ursprünglichen Wert von malloc zurückgegeben zurückgegeben; Das brauchst du, wenn es Zeit ist, free() anzurufen.

Schließlich erfordert der Formatbezeichner %p ein Argument vom Typ void*. einen anderen Zeigertyp Passing ist wahrscheinlich zu „arbeiten“, aber man sollte es wirklich zu gieße void*:

printf("%p\n", (void*)l++); 
+0

Perfekt. Danke für die zusätzlichen Tipps. – lmlf

+0

Kudos für 'long * l = malloc (3 * sizeof * l);' statt 'long * l = malloc (3 * sizeof (lang));' – chux

2

Sie Opfer einer Fehlschluss gefallen sind. Sie analysieren nicht, was malloc zurückgegeben hat. Sie sehen, dass das Inkrement weiß, wie der Zeiger basierend auf der Größe des Variablentyps richtig inkrementiert wird. Nichts über einen malloc-Aufruf sagt Ihnen, wie viel RAM tatsächlich zugewiesen wurde.

5

Fehle ich etwas?

Ja, Sie vermissen den Punkt völlig.

Sie testen Zeigerarithmetik, die in Bezug auf die Größe des spitzen Typs definiert ist. Das hat absolut nichts mit der Menge an Speicher zu tun, die von malloc() zugewiesen wird, oder sogar, ob der betreffende Zeiger überhaupt auf eine gültige Adresse zeigt.

Verwandte Themen