2010-04-28 6 views
8

gcc 4.4.1 c89Verwendung von sizeof mit einem dynamisch zugewiesenen Array

Ich habe den folgenden Code-Schnipsel:

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

char *buffer = malloc(10240); 
/* Check for memory error */ 
if(!buffer) 
{ 
    fprintf(stderr, "Memory error\n"); 
    return 1; 
} 
printf("sizeof(buffer) [ %d ]\n", sizeof(buffer)); 

jedoch die sizeof (Puffer) immer druckt 4. Ich weiß, dass ein char * ist nur 4 Bytes. Allerdings habe ich den Speicher für 10kb reserviert. Sollte also nicht die Größe 10240 sein? Ich frage mich, denke ich gerade hier?

Vielen Dank für Ihre Anregungen,

+2

Zum größten Teil hat der C-Compiler (für jede Version) keine Ahnung, was die Funktion 'malloc' tatsächlich tut oder verwendet. Alles, was es weiß, ist, dass es eine vorzeichenlose Ganzzahl (size_t) benötigt und einen void-Zeiger zurückgibt. Es könnte seinen Parameter verwenden, um den Zufallszahlengenerator zu setzen und eine Zufallszahl auf ein '(void *)' für alle Compiler-Sorgen zu werfen, so dass der Compiler nicht wissen kann, auf welche Größe der Speicher zeigt. – nategoose

Antwort

14

Sie fragen nach der Größe einer char*, die tatsächlich 4 ist, nicht die Größe des Puffers. Der sizeof-Operator kann die Größe eines dynamisch zugewiesenen Puffers nicht zurückgeben, sondern nur die Größe der zum Kompilierungszeitpunkt bekannten statischen Typen und Strukturen.

+2

'sizeof' kann die Größe eines dynamischen Puffers für Arrays variabler Länge in C99 zurückgeben. –

+0

Gibt es unter c89 eine Methode, mit der Sie herausfinden können, wie viel Speicher mit einem dynamisch zugewiesenen Puffer belegt wurde? Vielen Dank. – ant2009

+2

@Carl - VLAs sind nicht dynamisch. Sie sind "variable Länge", da ihre Länge zur Laufzeit berechnet werden kann, aber nicht "variable Länge", da ihre Länge ändern kann. Sie sind immer noch stackbasierte Arrays, weshalb "sizeof" für sie definiert ist. –

9

sizeof nicht auf dynamische Zuweisungen funktioniert (mit einigen Ausnahmen in C99). Ihre Verwendung von sizeof hier gibt Ihnen nur die Größe des Zeigers. Dieser Code wird Ihnen das gewünschte Ergebnis:

char buffer[10240]; 
printf("sizeof(buffer) [ %d ]\n", sizeof(buffer)); 

Wenn malloc() erfolgreich ist, der Speicher, auf zumindest so groß ist wie Sie gefragt, also gibt es keinen Grund, über die tatsächlichen Größe zugeordnet zu kümmern.

Außerdem haben Sie 10 kB zugewiesen, nicht 1 kB.

+0

Dieser Code ist mehr als ein wenig gefährlich: Er reserviert den Puffer auf dem Stack, nicht den Heap. Wenn Sie zulassen, dass Zeiger auf diesen Puffer aus der Funktion, die es deklariert, gehen, sind Sie auf dem Weg zur Stapelbeschädigung (und abhängig davon, wie lange Ihr Programm läuft, Heap-Beschädigung und/oder ein Segmentierungsfehler). – Anon

+2

@Anon - Es ist nicht gefährlich, es löst nur das Problem auf andere Weise. Das OP hatte keine Anforderungen, den Puffer von einer Funktion zurückzugeben. –

+0

Und was genau ist das OP-Problem?Scheint mir, dass es die Größe einer Heap-allokierten Struktur verfolgt. Das Vorschlagen, dass das OP eine Stapel zugewiesene Struktur verwendet, ist keine Lösung für dieses Problem. – Anon

3

Es liegt an Ihnen, die Größe des Speichers zu verfolgen, wenn Sie sie benötigen. Der von malloc zurückgegebene Speicher ist nur ein Zeiger auf "nicht initialisierte" Daten. Der Operator sizeof arbeitet nur an der Variablen buffer.

+0

Sicherlich kennt die Laufzeitumgebung die Größe des zugewiesenen Puffers (weil 'free (void *)' nicht nach der Größe fragt), also warum sollten wir selbst nachsehen müssen? – Dai

+0

Der zugrunde liegende Speicherverwaltungscode hat fast sicher die Größe, es sei denn, er verfügt über einen magischen Algorithmus zum Freigeben, der keine Größe erfordert. Aber diese Information wird nicht offengelegt. –

+0

Gibt es einen Grund, dass Daten nicht offengelegt werden? – Dai

2

Ersetzen Sie Ihre sizeof durch malloc_usable_size (die Manpage gibt an, dass dies nicht tragbar ist, daher möglicherweise nicht mit Ihrer bestimmten C-Implementierung verfügbar).

+1

'malloc_userable_size()' ist sehr nicht portabel. Ich habe es nicht auf OS X Leopard. Wie auch immer, das Vertrauen darauf ist in erster Linie eine schreckliche Idee (wie auch in der Manpage angegeben). –

+0

HINWEIS: Wenn Sie nicht auf Portabilität und sind auf OSX (oder jemand anderes kümmerte sich nicht, und Sie sind mit der Portierung auf OSX stecken) malloc_size von ist Ihr Mann für den Job. – Stripes

3

Nr. buffer ist ein char *. Es ist ein Zeiger auf char Daten. Der Zeiger benötigt nur 4 Bytes (auf Ihrem System).

Es zeigt auf 10240 Bytes von Daten (die übrigens nicht 1 KB ist. Mehr wie 10 KB), aber der Zeiger weiß nicht, dass. Bedenken Sie:

int a1[3] = {0, 1, 2}; 
int a2[5] = {0, 1, 2, 3, 4}; 

int *p = a1; 
// sizeof a1 == 12 (3 * sizeof(int)) 
// but sizeof p == 4 
p = a2 
// sizeof a2 == 20 
// sizeof p still == 4 

Es ist der größte Unterschied zwischen Arrays und Zeiger. Wenn es auf diese Weise nicht funktionierte, würde sich sizeof p im obigen Code ändern, was für eine Kompilierzeitkonstante nicht sinnvoll ist.