Programowanie w C: malloc () wewnątrz innej funkcji

Potrzebuję pomocy przy malloc() wewnątrz innej funkcji.

Przekazuję wskaźnik i Rozmiar do funkcji z mojego main() i chciałbym przydzielić pamięć dla tego wskaźnika dynamicznie używając malloc() z wewnątrz tej wywołanej funkcji, ale widzę to.... pamięć, która jest przydzielana, jest dla wskaźnika zadeklarowanego w mojej wywołanej funkcji, a nie dla wskaźnika, który jest wewnątrz main().

Jak przekazać wskaźnik do funkcja i przydzielić pamięć dla przekazanego wskaźnika z wnętrza wywołanej funkcji?


Napisałem następujący kod i otrzymuję wynik, jak pokazano poniżej.

Źródło:

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

WYJŚCIE PROGRAMU:

Point1: Memory allocated ptr: 262144 bytes
Point2: Memory allocated input_image: 0 bytes
Author: Jonathan Leffler, 2010-05-15

8 answers

Musisz przekazać wskaźnik do wskaźnika jako parametr do swojej funkcji.

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; 
} 
 61
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-31 18:18:00

Jak przekazać wskaźnik do funkcja i przydzielanie pamięci dla przekazywany wskaźnik od wewnątrz wywołanego funkcja?

Zadaj sobie pytanie: gdybyś musiał napisać funkcję, która musiałaby zwrócić int, Jak byś to zrobił?

Zwróciłbyś go bezpośrednio:

int foo(void)
{
    return 42;
}

Lub zwróć go poprzez parametr wyjściowy, dodając poziom indrection (tj. używając int* zamiast int):

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

Więc kiedy zwracasz typ wskaźnika (T*), to to samo: albo zwracasz typ wskaźnika bezpośrednio:

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

Lub dodajesz jeden poziom indrection:

void foo(T** out)
{
    assert(out != NULL);
    *out = malloc(...);
}
 79
Author: jamesdlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-25 20:12:13

Jeśli chcesz, aby Twoja funkcja zmodyfikowała sam wskaźnik, musisz przekazać go jako wskaźnik do wskaźnika. Oto uproszczony przykład:

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);
}
 7
Author: Matti Virkkunen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 22:49:21

Musisz przekazać wskaźnik przez referencję, a nie przez kopię, parametr w funkcji alloc_pixelswymaga ampersand&, aby przekazać z powrotem adres wskaźnika - to jest wywołanie przez referencję w języku C speak.

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

Skomentowałem dwie linijki free(ptr) i " błąd: ..."wewnątrz alloc_pixels funkcji, ponieważ jest to mylące. Nie trzeba free Wskaźnik, jeśli alokacja pamięci nie powiodła się.

Edit: po obejrzeniu msdn link dostarczony przez OP, sugestia, próbka kodu jest taka sama jak wcześniej w mojej odpowiedzi.... ale...Zmień specyfikator formatu na %u dla typu size_t, w wywołaniu printf(...) w wywołaniu 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");     

}
 3
Author: t0mm13b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-15 10:59:33

To nie ma sensu:

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

alloc_pixels zwraca a signed char (ERROR or NO_ERROR) i porównujesz go z NULL (który ma być używany do wskaźników).

Jeśli chcesz, aby input_image została zmieniona, musisz przekazać do niej wskaźnik do alloc_pixels. alloc_pixels podpis będzie następujący:

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

Nazwałbyś to tak:

alloc_pixels(&input_image, bmp_image_size);

I alokacja pamięci

*ptr = malloc(size);
 2
Author: Bertrand Marron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 22:50:27

W Twoim kodzie początkowym , kiedy przekazywałeś input_image do funkcji alloc_pixels, kompilator tworzył jej kopię (tj. ptr) i przechowywał wartość na stosie. Przypisujesz wartość zwróconą przez malloc do PST. Wartość ta jest tracona, gdy funkcja powróci do main i stos się odwija. Tak więc pamięć jest nadal przydzielana na stercie, ale lokalizacja pamięci nigdy nie została zapisana (lub przypisana do )input_image, stąd problem.

Możesz zmienić podpis funkcji alloc_pixels, co byłoby prostsze do zrozumienia i nie będzie wymagało dodatkowej zmiennej "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;
}

Możesz wywołać powyższą funkcję w main:

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
Author: juventus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-15 06:42:42

Przypisanie parametrów będzie działać tylko wtedy, gdy ustawisz wartość na jej adres .

Są 2 punkty, które powinieneś wiedzieć, zanim spróbujesz rozwiązać ten problem:
1. C Funkcja: wszystkie parametry przekazane do funkcji będą kopiowane w funkcji.

Oznacza to, że każde przypisanie dokonane w funkcji nie będzie miało wpływu na zmienne spoza funkcji, pracujesz nad kopią właściwie:

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

Więc, jeśli chcesz zmienić i w funkcji, musisz znać różnicę między rzeczą a jej kopią:

Kopia dzieliła wartość z rzeczą, ale nie adres .

I to ich jedyna różnica.

Więc jedynym sposobem na zmianę i w funkcji jest użycie adresu i.

Na przykład, istnieje nowa funkcja fun_addr:

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

W ten sposób, można zmienić i ' S wartość.

  1. malloc :

Kluczowym punktem funkcji fun_addr jest przekazanie adresu do funkcji. I możesz zmienić wartość przechowywaną w tym adresie.

Co zrobi malloc?

Malloc przydzieli nową przestrzeń pamięci i zwróci wskaźnik wskazujący na ten adres z powrotem .

Spójrz na tę instrukcję:

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

To co robisz to niech wartość array jest równa adresowi zwracanemu przez malloc.

Widzisz? Jest to to samo pytanie, trwale przypisując wartość parametrowi przekazywanemu funkcji. W tym momencie wartością jest address.

Teraz Przypisz adres (zwrócony przez malloc) do adresu (przechowuje stary adres).

Więc kod powinien być:

void fun_addr_addr(int **p) {
    *p = (int*) malloc(sizeof(int) * SIZE);
}
To zadziała.
 1
Author: VELVETDETH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-21 11:10:34

Jedyny sposób, w jaki mogłem uzyskać wskaźnik do rozwiązania wskaźnika, aby działał na podobny problem, który miałem dla tej funkcji

    BOOL OpenBitmap2 ( LPCTSTR pszFileName, char** pszBMPFile)  

Było poprzez przypisanie tymczasowego wskaźnika do przechowywania adresu

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

Następnie przypisanie go

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

Każdy komentarz, dlaczego używanie "* pszBMPFile" bezpośrednio z GlobalAlloc nie działa, będzie mile widziany. Odpowiedziałem na własne pytanie. Zapomniałem przenieść " * " z pszBMPFile w innych linijkach kodu. Dobre lekcje z wszystkich współpracownicy. Wielkie dzięki.

 1
Author: PeterS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-25 23:18:28