web-dev-qa-db-fra.com

Programmation C: malloc () dans une autre fonction

J'ai besoin d'aide avec malloc() dans une autre fonction .

Je passe un pointeur et taille à la fonction de mon main() et je voudrais allouer dynamiquement de la mémoire pour ce pointeur en utilisant malloc() de l'intérieur de cette fonction appelée, mais ce que je vois, c'est que .... la mémoire, qui est allouée, est pour le pointeur déclaré dans ma fonction appelée et non pour le pointeur qui est à l'intérieur de main().

Comment dois-je passer un pointeur à une fonction et allouer de la mémoire pour le pointeur passé de l'intérieur de la fonction appelée?


J'ai écrit le code suivant et j'obtiens la sortie comme indiqué ci-dessous.

SOURCE:

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;
}

SORTIE DU PROGRAMME:

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

Vous devez passer un pointeur vers un pointeur comme paramètre de votre fonction.

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; 
} 
71
Mark Ransom

Comment dois-je passer un pointeur à une fonction et allouer de la mémoire pour le pointeur passé depuis l'intérieur de la fonction appelée?

Demandez-vous ceci: si vous deviez écrire une fonction qui devait retourner un int, comment feriez-vous?

Vous pouvez soit le retourner directement:

int foo(void)
{
    return 42;
}

ou le renvoyer via un paramètre de sortie en ajoutant un niveau de indirection (c'est-à-dire en utilisant un int* au lieu de int):

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

Ainsi, lorsque vous renvoyez un type de pointeur (T*), c'est la même chose: vous retournez soit directement le type de pointeur:

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

ou vous ajoutez un niveau d'indirection:

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

Si vous souhaitez que votre fonction modifie le pointeur lui-même, vous devrez le passer comme pointeur à un pointeur. Voici un exemple simplifié:

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);
}
8
Matti Virkkunen

Vous devez passer le pointeur par référence , pas par copie, le paramètre de la fonction alloc_pixels requiert que l'esperluette & remette l'adresse du pointeur - c'est-à-dire appel par référence en C parler.

 main () 
 {
 unsigned char * input_image; 
 unsigned int bmp_image_size = 262144; 
 
 if (alloc_pixels (& input_image , bmp_image_size) == NULL) 
 printf ("\ nPoint2: Mémoire allouée:% d octets", _ msize (input_image)); 
 sinon 
 printf ("\ nPoint3: Mémoire Pas alloué"); 
 
} 
 
 caractère signé alloc_pixels (caractère non signé ** ptr, taille int non signé) 
 {
 état du caractère signé = NO_ERROR; 
 * Ptr = NULL; 
 
 * Ptr = (caractère non signé *) malloc (taille); 
 
 If ((* ptr ) == NULL) 
 {
 Status = ERROR; 
/* Free (ptr); 
 Printf ("\ nERROR: L'allocation de mémoire ne s'est pas terminée avec succès! "); */
} 
 
 printf ("\ nPoint1: Mémoire allouée:% d octets", _ msize (* ptr)); 
 
 return statut;
}

J'ai commenté les deux lignes free(ptr) et "ERREUR: ..." dans la fonction alloc_pixels Car c'est déroutant. Vous n'avez pas besoin de free un pointeur si l'allocation de mémoire a échoué.

Edit: Après avoir regardé le lien msdn fourni par OP, une suggestion, l'exemple de code est le même que précédemment dans mon réponse .... mais ... changez le spécificateur de format en %u pour le type size_t, dans la fonction printf(...) appelez main().

 main () 
 {
 unsigned char * input_image; 
 unsigned int bmp_image_size = 262144; 
 
 if (alloc_pixels (& input_image , bmp_image_size) == NULL) 
 printf ("\ nPoint2: Mémoire allouée:% u octets", _ msize (input_image)); 
 sinon 
 printf ("\ nPoint3: Mémoire Pas alloué"); 
 
} 
4
t0mm13b

Cela n'a pas de sens :

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

alloc_pixels renvoie un signed char (ERROR ou NO_ERROR) et vous le comparez à NULL (qui est censé être utilisé pour les pointeurs).

Si tu veux input_image à modifier, vous devez lui passer un pointeur sur alloc_pixels. alloc_pixels la signature serait la suivante:

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

Vous l'appeleriez ainsi:

alloc_pixels(&input_image, bmp_image_size);

Et l'allocation de mémoire

*ptr = malloc(size);
2
Bertrand Marron

Dans votre code initial, lorsque vous passiez input_image à la fonction alloc_pixels, le compilateur en créait une copie (c'est-à-dire ptr) et stockait la valeur sur la pile. Vous affectez la valeur renvoyée par malloc à ptr. Cette valeur est perdue une fois que la fonction revient à main et que la pile se déroule. Ainsi, la mémoire est toujours allouée sur le tas, mais l'emplacement de la mémoire n'a jamais été stocké dans (ou attribué à) input_image, d'où le problème.

Vous pouvez changer la signature de la fonction alloc_pixels qui serait plus simple à comprendre, et vous n'aurez pas besoin de la variable supplémentaire "status" également.

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;
}

Vous pouvez appeler la fonction ci-dessus en principal:

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;

}
1
juventus

L'affectation des paramètres ne fonctionnera que si vous définissez la valeur sur son adresse.

Vous devez connaître 2 points avant de tenter de résoudre ce problème:
1. Fonction C: Tous les paramètres que vous avez passés à la fonction seront une copie dans la fonction.

Cela signifie que chaque affectation que vous avez effectuée dans la fonction n'affectera pas les variables en dehors de la fonction, vous travaillez en fait sur copie:

int i = 1;
fun(i);
printf("%d\n", i);
//no matter what kind of changes you've made to i in fun, i's value will be 1

Donc, si vous voulez changer i dans la fonction, vous devez connaître la différence entre la chose et sa copie:

La copie partageait la valeur avec la chose, mais pas la adresse.

Et c'est leur seule différence.

Donc, la seule façon de changer i dans la fonction est d'utiliser l'adresse de i.

Par exemple, il y a une nouvelle fonction fun_addr:

void fun_addr(int *i) {
    *i = some_value;
}

De cette façon, vous pouvez modifier la valeur de i.

  1. malloc:

Le point clé de la fonction fun_addr est que vous avez passé une adresse à la fonction. Et vous pouvez modifier la valeur stockée dans cette adresse.

Que fera malloc?

malloc allouera un nouvel espace mémoire, et retourner le pointeur pointé vers cette adresse.

Regardez cette instruction:

int *array = (int*) malloc(sizeof(int) * SIZE);

Ce que vous faites, c'est laisser la valeur du tableau égale à l'adresse retournée par malloc.

Voir? Il s'agit de la même question, en attribuant de façon permanente une valeur au paramètre passé à la fonction. À ce stade, la valeur est address.

Maintenant, affectez l'adresse (retournée par malloc) à l'adresse (stocke l'ancienne adresse).

Le code devrait donc être:

void fun_addr_addr(int **p) {
    *p = (int*) malloc(sizeof(int) * SIZE);
}

Celui-ci fonctionnera.

1
VELVETDETH

La seule façon dont je pouvais obtenir un pointeur vers une solution de pointeur pour travailler avec un problème similaire que je rencontrais pour cette fonction

    BOOL OpenBitmap2 ( LPCTSTR pszFileName, char** pszBMPFile)  

Était en affectant un pointeur temporaire pour stocker l'adresse

    char* BMPFile;
    { BMPFile = (char*)GlobalAlloc(GPTR, dwFileSize + 1);   // allocate storage using GlobalAlloc + 1 for null term string

puis le réaffecter

    {* pszBMPFile = BMPFile; return (0);} // Error = False

Tout commentaire expliquant pourquoi l'utilisation de "* pszBMPFile" directement avec GlobalAlloc n'a pas fonctionné serait apprécié. J'ai répondu à ma propre question. J'ai oublié de faire passer le "*" avec pszBMPFile dans les autres lignes de code. Bonnes leçons de tous les contributeurs. Merci beaucoup.

1
PeterS