Программирование на C: malloc () внутри другой функции - PullRequest
59 голосов
/ 15 мая 2010

Мне нужна помощь с malloc() внутри другой функции .

Я передаю указатель и size в функцию из моего main(), и я хотел бы выделить память для этого указателя динамически, используя malloc() изнутри функция, но я вижу, что .... память, которая выделяется, предназначена для указателя, объявленного в моей вызываемой функции, а не для указателя, который находится внутри main().

Как передать указатель на функцию и выделить память для переданного указателя из вызываемой функции ?


Я написал следующий код и получаю вывод, как показано ниже.

ИСТОЧНИК:

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

ВЫХОД ПРОГРАММЫ:

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

Ответы [ 8 ]

88 голосов
/ 15 мая 2010

Как мне передать указатель на функционировать и распределять память для передал указатель изнутри вызываемого функционировать?

Задайте себе вопрос: если бы вам пришлось написать функцию, которая должна возвращать int, как бы вы это сделали?

Вы бы либо вернули его напрямую:

int foo(void)
{
    return 42;
}

или вернуть его через выходной параметр, добавив уровень косвенность (то есть, используя int* вместо int):

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

Поэтому, когда вы возвращаете тип указателя (T*), это то же самое: вы либо возвращаете тип указателя напрямую:

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

или вы добавляете один уровень косвенности:

void foo(T** out)
{
    assert(out != NULL);
    *out = malloc(...);
}
70 голосов
/ 15 мая 2010

Вам нужно передать указатель на указатель в качестве параметра вашей функции.

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; 
} 
8 голосов
/ 15 мая 2010

Если вы хотите, чтобы ваша функция изменяла сам указатель, вам нужно будет передать его как указатель на указатель. Вот упрощенный пример:

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);
}
3 голосов
/ 15 мая 2010

Вам нужно передать указатель по ссылке , а не при копировании , параметр в функции alloc_pixels требует, чтобы знак амперсанда & возвращал адрес указателя звоните по ссылке на языке C.

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

Я закомментировал две строки free(ptr) и "ОШИБКА: ..." внутри функции alloc_pixels, поскольку это сбивает с толку. Вам не нужно free указатель, если выделение памяти не удалось.

Редактировать: После просмотра ссылки msdn , предоставленной OP, предложение, пример кода такой же, как и ранее в моем ответе .... но ... изменить спецификатор формата %u для типа size_t, при вызове printf(...) в 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");     

}
2 голосов
/ 15 мая 2010

Это не имеет смысла:

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

alloc_pixels возвращает signed char (ERROR или NO_ERROR), и вы сравниваете его с NULL (который предполагается использовать для указателей).

Если вы хотите изменить input_image, вам нужно передать указатель на него alloc_pixels. alloc_pixels подпись будет следующей:

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

Вы бы назвали это так:

alloc_pixels(&input_image, bmp_image_size);

А выделение памяти

*ptr = malloc(size);
1 голос
/ 25 ноября 2017

Единственный способ получить указатель на решение с указателем для решения аналогичной проблемы, с которой я столкнулся для этой функции

    BOOL OpenBitmap2 ( LPCTSTR pszFileName, char** pszBMPFile)  

Был назначен временный указатель для хранения адреса

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

затем переназначение

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

Любой комментарий о том, почему использование "* pszBMPFile" напрямую с GlobalAlloc не работает, приветствуется. Я ответил на свой вопрос. Я забыл перенести «*» через pszBMPFile в других строках кода. Хорошие уроки от всех участников. Большое спасибо.

1 голос
/ 21 сентября 2014

Назначение параметров будет работать, только если вы установите значение для его address .

Есть 2 момента, которые вы должны знать, прежде чем пытаться решить эту проблему:
1. C Функция : Все параметры, которые вы передали в функцию, будут скопированы в функцию.

Это означает, что каждое присвоение, которое вы сделали в функции, не будет влиять на переменные вне функции, вы работаете над copy на самом деле:

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

Итак, если вы хотите изменить i в функции, вам нужно знать разницу между вещью и ее копией:

Копия поделилась значением с вещью, но не адресом .

И в этом их единственное отличие.

Таким образом, единственный способ изменить i в функции - использовать адрес i.

Например, есть новая функция fun_addr:

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

Таким образом, вы можете изменить значение i.

  1. malloc :

Ключевым моментом в функции fun_addr является то, что вы передали адрес функции. И вы можете изменить значение, хранящееся в этом адресе.

Что будет делать malloc?

malloc выделит новое пространство памяти, а вернет указатель, указывающий на этот адрес, обратно .

Посмотрите на эту инструкцию:

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

То, что вы делаете, - это пусть значение массива равно адресу, возвращенному malloc.

См? Это тот же вопрос, который постоянно присваивает значение параметру, передаваемому функции. На данный момент значение равно address.

Теперь присвойте адрес (возвращаемый malloc) этому адресу (сохраняет старый адрес).

Так что код должен быть:

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

Этот будет работать.

1 голос
/ 15 мая 2010

В вашем исходном коде, когда вы передавали input_image в функцию alloc_pixels, компилятор создавал его копию (т.е. ptr) и сохранял значение в стеке. Вы присваиваете значение, возвращаемое malloc для ptr. Это значение теряется, когда функция возвращается к основному, и стек раскручивается. Таким образом, память все еще выделяется в куче, но ячейка памяти никогда не сохранялась (или не назначалась) в input_image, поэтому проблема.

Вы можете изменить сигнатуру функции alloc_pixels, которая будет проще для понимания, и вам также не потребуется дополнительная переменная '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;
}

Вы можете вызвать вышеуказанную функцию в основном:

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;

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...