C-Programmierung: malloc() innerhalb einer anderen Funktion
Lesezeit: 9 Minuten
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;
}
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
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
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
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().
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.
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);
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“.