2011-01-06 6 views
1

Ich schreibe eine Funktion, die die Größe eines dynamischen Speicherobjekts erhöht, das mit malloc erstellt wird. Die Funktion sollte als Argumente einen Zeiger auf den Speicherblock nehmen, der erhöht werden soll, die aktuelle Größe des Blocks und den Betrag, um den der Block erhöht wird.Wie wird die Größe verschiedener Arten von Typen in der gleichen Funktion mit C erhalten?

Etwas wie folgt aus:

int getMoreSpace(void **pnt, int size, int add) { 
    xxxxxx *tmp; /* a pointer to the same as pnt */ 
    if (tmp = realloc(pnt, (size+add)*sizeof(xxxxxx))) { /* get size of what pnt points to */ 
     *pnt=tmp; 
     return 1; 
    else return 0; 
} 

Das Problem ist, dass ich die Funktion wollen nicht arbeiten, ganz gleich, was pnt Punkte. Wie erreiche ich das?

Antwort

9

Dieser Funktionstyp kann möglicherweise nicht funktionieren, da lokal ist und der neue Zeiger verloren geht, sobald die Funktion zurückkehrt. Sie könnten ein Argument vom Typ xxxxxx ** nehmen, damit Sie den Zeiger aktualisieren können, aber dann müssen Sie nur einen einzigen Typ unterstützen.

Das eigentliche Problem ist, dass Sie einen unnötigen und schädlichen Wrapper für realloc schreiben. Verwenden Sie einfach realloc direkt, wie es verwendet werden sollte. Es gibt keinen Weg, es einfacher oder effizienter zu machen, indem man es einpackt; es ist schon so einfach wie möglich.

+0

Ich verstehe nicht wirklich, was Sie sagen. Warum ist es wichtig, dass pnt lokal ist? Ich brauche es nur, bis die Funktion zurückkehrt. Warum ist diese Hülle auch schädlich? Ich mache diese Art von Größenzunahme mehrere Male in meinem Programm unter verschiedenen Umständen, soweit ich sehen kann, macht diese Funktion nur meinen Programmierer sauberer und einfacher, weil es das Tippen in der gleichen Sache viele Male beseitigt (ist das nicht der Punkt von Funktionen sowieso?). – paldepind

+0

Ich bin nicht 100% sicher, aber ich denke, dass es in C keinen "lokalen" Zeiger gibt. –

+4

@Stefanos: Funktionsargumente sind "lokale Variablen" in dem Sinne, dass sie den Gültigkeitsbereich der Funktion verlassen . Das Zuweisen eines neuen Werts zu "ptr" hat keine Auswirkungen; Tatsächlich kann und sollte der Compiler die Zuweisung optimieren. –

2

Sie übergeben die Größe als Argument. Sie können einen Komfort-Makro verwenden, um es die gleichen wie Ihre Funktion aussehen:

#define getMoreSpace(P, SZ, ADD) getMoreSpaceFunc(&(P), sizeof(*(P)), (SZ), (ADD)) 

int getMoreSpace(void **pnt, size_t elem_size, int size, int add) { 
    *pnt = ... 
} 

bearbeiten zu zeigen, dass in Ihrem Makro müßte auch Call-by-reference Semantik hinzuzufügen.

+0

Warum verwenden Sie ein Makro? Funktioniert sizeof nur, indem er eine Variable übergibt? Ich akzeptierte nur einen Typ als Argument? – paldepind

+0

'sizeof' ist ein Operator. Es muss in der Lage sein, den Typ zu sehen. Das Makro ersetzt als Text im ursprünglichen Code, wo der Typ der Variablen sichtbar ist. In Ihrer Funktion verlieren Sie immer noch Typinformationen, aber das Makro wurde in der für Sie gültigen Größe übergeben. Weiter können Sie das Makro verwenden (wie ich in der Bearbeitung dargestellt habe), um die Adresse des Zielzeigers für Sie zu nehmen. –

+0

... auch habe ich die Antwort von R gewählt, weil ich nicht glaube, dass Sie das tun sollten, aber ich dachte, eine technische Antwort auf Ihre Frage wäre auch aufschlussreich. –

1

Pass in der Elementgröße als separater Parameter:

int getMoreSpace(void **pnt, int size, int add, size_t eltSize) 
{  
    void *tmp; 
    if (tmp = realloc(pnt, (size+add)*eltSize)) 
    { 
    *pnt=tmp; 
    return 1; 
    } 
    else 
    return 0; 
} 
... 

int *p = malloc(100 * sizeof *p); 
... 
if (!getMoreSpace(&p, 100, 20, sizeof *p)) 
{ 
    // panic 
} 

Es ist die einfachste Lösung, wenn nicht die eleganteste. C eignet sich nicht nur für dynamische Informationen.

bearbeiten

die Art der pnt als Antwort auf Steve Kommentar geändert.

Wie Caf darauf hinweist, wird dies nicht funktionieren, selbst mit dem "Fix" per Steve. R. hat recht; tu das nicht.

+0

Dies funktioniert nicht ohne die Verwendung von Zeigern auf Zeiger.* p wird niemals den von realloc zurückgegebenen Wert zugewiesen. –

+0

@Steve Melvin. Duh. Ich wusste, dass. Ja wirklich. Ich werde das Beispiel bearbeiten, um das zu beheben. Wow, zwei Downvotes an einem Tag; Das ist ein Rekord für mich. –

+0

Es ist nicht erlaubt, ein Objekt vom Typ 'int *' mit einem Lvalue vom Typ 'void *' zu modifizieren - ein solcher Code hat ein undefiniertes Verhalten. – caf

Verwandte Themen