C-Programmierung: malloc() innerhalb einer anderen Funktion

Lesezeit: 9 Minuten

Benutzeravatar von HaggarTheHorrible
Haggar TheHorrible

Ich brauche Hilfe bei malloc() innerhalb einer anderen Funktion.

Ich passiere a Zeiger und Größe zur Funktion von my main() und ich möchte Speicher für diesen Zeiger dynamisch zuweisen malloc() aus dieser aufgerufenen Funktion, aber was ich sehe, ist, dass …. der Speicher, der zugewiesen wird, für den in meiner aufgerufenen Funktion deklarierten Zeiger und nicht für den Zeiger innerhalb der Funktion bestimmt ist main().

Wie soll ich einen Zeiger an eine Funktion übergeben und Speicher für den übergebenen Zeiger zuweisen? aus der aufgerufenen Funktion?


Ich habe den folgenden Code geschrieben und erhalte die Ausgabe wie unten gezeigt.

QUELLE:

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char *ptr, unsigned int size)
{
    signed char status = NO_ERROR;
    ptr = NULL;

    ptr = (unsigned char*)malloc(size);

    if(ptr== NULL)
    {
        status = ERROR;
        free(ptr);
        printf("\nERROR: Memory allocation did not complete successfully!");
    }

    printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));

    return status;
}

PROGRAMMAUSGABE:

Point1: Memory allocated ptr: 262144 bytes
Point2: Memory allocated input_image: 0 bytes

Benutzeravatar von jamesdlin
jamesdlin

Wie soll ich einen Zeiger an eine Funktion übergeben und Speicher für den übergebenen Zeiger innerhalb der aufgerufenen Funktion zuweisen?

Stellen Sie sich folgende Frage: Wenn Sie eine Funktion schreiben müssten, die ein zurückgeben müsste intwie würdest du es machen?

Sie würden es entweder direkt zurückgeben:

int foo(void)
{
    return 42;
}

oder geben Sie es über einen Ausgabeparameter zurück, indem Sie eine Ebene von hinzufügen indirekt (d.h. mit einem int* Anstatt von int):

void foo(int* out)
{
    assert(out != NULL);
    *out = 42;
}

Wenn Sie also einen Zeigertyp zurückgeben (T*), ist es dasselbe: Sie geben entweder den Zeigertyp direkt zurück:

T* foo(void)
{
    T* p = malloc(...);
    return p;
}

oder Sie fügen eine Indirektionsebene hinzu:

void foo(T** out)
{
    assert(out != NULL);
    *out = malloc(...);
}

  • Danke für die Erklärung, die ich zu schnell liefern musste.

    – Markieren Sie Lösegeld

    15. Mai 2010 um 1:44 Uhr

  • +1, ich liebe alles außer der Behauptung, aber für eine so einfache Demonstration ist es in Ordnung.

    – Tim Post

    15. Mai 2010 um 6:47 Uhr

  • Ich mag die Behauptung; es ist ein Vertragsbestandteil für die Funktion, die der Anrufer systematisch richtig bekommen soll. Natürlich könnte noch subtilerer Code eine NULL ergeben out zulässig, wenn es einem optionalen Ausgangsparameter entspricht. Aber dafür ist es nicht nötig alloc_pixels; Die Frage erfordert keine solche Raffinesse.

    – Donal Fellows

    15. Mai 2010 um 6:56 Uhr

  • Ist es sicher, innerhalb der aufrufenden Funktion (in diesem Fall main) free(*out) zu verwenden?

    – William Everett

    9. Januar 2014 um 16:51 Uhr

  • @Pinyaka: Es ist sicher für den Anrufer anzurufen free() auf dem resultierenden Zeiger (wie sonst würde der Aufrufer den zugewiesenen Speicher freigeben?). Allerdings würde der Anrufer entweder tun T* out = foo(); (in der ersten Form) oder T* out; foo(&out); (in der zweiten Form). In beiden Fällen müsste der Anrufer anrufen free(out)nicht free(*out).

    – jamesdlin

    9. Januar 2014 um 17:29 Uhr

Benutzeravatar von Mark Ransom
Mark Lösegeld

Sie müssen einen Zeiger auf einen Zeiger als Parameter an Ihre Funktion übergeben.

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size) == NO_ERROR)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char **ptr, unsigned int size) 
{ 
    signed char status = NO_ERROR; 
    *ptr = NULL; 

    *ptr = (unsigned char*)malloc(size); 

    if(*ptr== NULL) 
    {
        status = ERROR; 
        free(*ptr);      /* this line is completely redundant */
        printf("\nERROR: Memory allocation did not complete successfully!"); 
    } 

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr)); 

    return status; 
} 

  • Warum rufen Sie kostenlos in einem bedingten Codeblock an, der garantiert einen NULL-Zeiger hat!?!? Die free(*ptr) wird, wenn von angerufen main() versuchen zu befreien input_image das war ähm, der Begriff entzieht sich mir … nicht dynamisch zugewiesen.

    – James Morris

    14. Mai 2010 um 22:45 Uhr


  • und @James: Ich habe getan, was von Mark und Matti vorgeschlagen wurde, aber diesmal geben sowohl mein _mize(input_image) in meiner main()- als auch _msize(**ptr) in meiner alloc_pixels(…)-Funktion die Größe als 0 zurück .. Wohingegen, wenn es _msize(*ptr) (single *) ist, 262144 zurückgibt.

    – HaggarTheHorrible

    14. Mai 2010 um 23:09 Uhr


  • @James Morris, ich habe gerade den Code kopiert, der in der Frage gepostet wurde, und die minimale Anzahl von Änderungen vorgenommen. Ich wollte mich nicht von der Hauptsache ablenken lassen.

    – Markieren Sie Lösegeld

    15. Mai 2010 um 1:50 Uhr

  • @vikramtheone, Entschuldigung, ich war etwas in Eile und habe diese Antwort nicht so vollständig gemacht, wie sie hätte sein sollen. Ich habe es bearbeitet, um vollständiger zu sein. Ich hoffe, Sie können sehen, wie es sich von Ihrem ursprünglichen Code unterscheidet und warum es so sein muss.

    – Markieren Sie Lösegeld

    15. Mai 2010 um 2:01 Uhr


  • Ich habe das gleiche auf MSVS versucht, aber es hat nicht funktioniert. input_image bleibt ‘bad pointer’. Was könnte der Grund sein?

    – Zeeshan

    7. April 2016 um 9:26 Uhr

Benutzeravatar von Matti Virkkunen
Matti Virkkunen

Wenn Sie möchten, dass Ihre Funktion den Zeiger selbst ändert, müssen Sie ihn als Zeiger an einen Zeiger übergeben. Hier ist ein vereinfachtes Beispiel:

void allocate_memory(char **ptr, size_t size) {
    void *memory = malloc(size);
    if (memory == NULL) {
        // ...error handling (btw, there's no need to call free() on a null pointer. It doesn't do anything.)
    }

    *ptr = (char *)memory;
}

int main() {
   char *data;
   allocate_memory(&data, 16);
}

  • Es ist sicher anzurufen free() bei einem Nullzeiger, worum geht es in diesem Kommentar?

    – Karl Norum

    14. Mai 2010 um 22:37 Uhr

  • @Carl Norum: Es ist sicher, aber sinnlos. IMO, Code, der nichts tut, führt nur zu Verwirrung für Leute, die ihn später lesen und sollte vermieden werden.

    – Matti Virkkunen

    14. Mai 2010 um 22:38 Uhr


  • @Matti Virkkunen: Leuten zu sagen, dass sie bei einem NULL-Zeiger nicht kostenlos anrufen sollen, ist sinnlos und Fehlinformationen – Sie verwirren die Leute, wenn sie Code sehen, der gegen Ihren Rat verstößt.

    – James Morris

    14. Mai 2010 um 22:43 Uhr


  • @James Morris: Gut, gut … gefällt dir der Wortlaut jetzt besser?

    – Matti Virkkunen

    14. Mai 2010 um 22:49 Uhr

  • @Carl: Ich bin auf (nicht sehr schöne) C-Bibliotheken gestoßen, die abgestürzt sind, wenn ich darum gebeten wurde free(NULL); also ist es sowieso gut zu vermeiden. (Nein, ich weiß nicht mehr welche. Es ist schon eine ganze Weile her.)

    – Donal Fellows

    14. Mai 2010 um 22:55 Uhr

Benutzeravatar von t0mm13b
t0mm13b

Sie müssen den Zeiger übergeben per Referenznicht per Kopieder Parameter in der Funktion alloc_pixels erfordert das kaufmännische Und &, um die Adresse des Zeigers zurückzugeben – das heißt Aufruf durch Referenz in C sprechen.

main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     

}

signed char alloc_pixels(unsigned char **ptr, unsigned int size)
{
    signed char status = NO_ERROR;
    *ptr = NULL;

    *ptr = (unsigned char*)malloc(size);

    if((*ptr) == NULL)
    {
        status = ERROR;
        /* free(ptr);
        printf("\nERROR: Memory allocation did not complete successfully!"); */
    }

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr));

    return status;
}

Ich habe die beiden Zeilen auskommentiert free(ptr) und “FEHLER: …” innerhalb der alloc_pixels funktionieren, da das verwirrend ist. Du brauchst nicht free ein Zeiger, wenn die Speicherzuweisung fehlgeschlagen ist.

Bearbeiten: Nach dem Betrachten der msdn Link von OP, ein Vorschlag, das Codebeispiel ist das gleiche wie zuvor in meiner Antwort … aber … ändern Sie den Formatbezeichner in %u für die size_t Typ, in der printf(...) anrufen main().

main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %u bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     

}

Benutzeravatar von Song WANG
Lied Wang

Wie in den anderen Antworten erwähnt, benötigen wir einen Zeiger auf den Zeiger. Aber wieso?

Wir müssen den Wert durch einen Zeiger übergeben, um den Wert ändern zu können. Wenn Sie eine ändern möchten intSie müssen es durch die passieren int*.

In dieser Frage ist der Wert, den wir ändern möchten, ein Zeiger int* (Zeiger geändert von NULL auf die Adresse des zugewiesenen Speichers), also müssen wir einen Zeiger auf den Zeiger übergeben int**.

Indem Sie folgten, pInt Innerhalb foo(int*) ist eine Kopie des Arguments. Wenn wir der lokalen Variablen Speicher zuweisen, wird diejenige in der main() ist intakt.

void foo(int* pInt)
{
   pInt = malloc(...);
}
int main()
{
   int* pInt;
   foo(pInt);
   return 0;
}

Also brauchen wir einen Zeiger auf Zeiger,

void foo(int** pInt)
{
   *pInt = malloc(...);
}
int main()
{
   int* pInt;
   foo(&pInt);
   return 0;
}

Das macht keinen Sinn :

if(alloc_pixels(input_image, bmp_image_size)==NULL) 

alloc_pixels gibt a zurück signed char (ERROR oder NO_ERROR) und Sie vergleichen es mit NULL (was für Zeiger verwendet werden soll).

Falls Sie es wollen input_image geändert werden, müssen Sie einen Zeiger darauf übergeben alloc_pixels.
alloc_pixels Unterschrift wäre folgende:

signed char alloc_pixels(unsigned char **ptr, unsigned int size)

Du würdest es so nennen:

alloc_pixels(&input_image, bmp_image_size);

Und die Speicherbelegung

*ptr = malloc(size);

Benutzeravatar von juventus
Juventus

Als Sie in Ihrem ursprünglichen Code input_image an die Funktion alloc_pixels übergeben haben, hat der Compiler eine Kopie davon erstellt (dh ptr) und den Wert auf dem Stapel gespeichert. Sie weisen ptr den von malloc zurückgegebenen Wert zu. Dieser Wert geht verloren, sobald die Funktion zu main zurückkehrt und der Stack entladen wird. Der Speicher wird also immer noch auf dem Heap zugewiesen, aber der Speicherort wurde nie in input_image gespeichert (oder ihm zugewiesen), daher das Problem.

Sie können die Signatur der Funktion alloc_pixels ändern, was einfacher zu verstehen wäre, und Sie benötigen auch nicht die zusätzliche Variable „status“.

unsigned char *alloc_pixels(unsigned int size)
{
    unsigned char *ptr = NULL;
    ptr = (unsigned char *)malloc(size);
    if (ptr != NULL)
       printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));
    return ptr;
}

Sie können die obige Funktion in main aufrufen:

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if((input_image = alloc_pixels(bmp_image_size))==NULL)
       printf("\nPoint3: Memory not allocated");    
   else
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image)); 
   return 0;

}

1418340cookie-checkC-Programmierung: malloc() innerhalb einer anderen Funktion

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy