it-roy-ru.com

Программирование на C: malloc () внутри другой функции

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

Я передаю указатель и размер в функцию из моей 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
59
HaggarTheHorrible

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

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

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

Задайте себе вопрос: если бы вам пришлось написать функцию, которая должна возвращать 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(...);
}
88
jamesdlin

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

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

Вам нужно передать указатель по ссылке , а не при копировании , параметр в функции 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: выделено памяти:% d байтов", _ msize (input_image)); 
 else 
 printf ("\ nPoint3: Память не выделено "); 
 
} 
 
 подписанный символ char alloc_pixels (unsigned char ** ptr, unsigned int size) 
 {
 подписанный символ char = NO_ERROR; 
 * Ptr = NULL; 
 
 * Ptr = (unsigned char *) malloc (size); 
 
 If ((* ptr ) == NULL) 
 {
 Status = ERROR; 
/* Free (ptr); 
 Printf ("\ nERROR: Распределение памяти не выполнено успешно! "); */
} 
 
 printf ("\ nPoint1: выделено памяти:% d байт", _ msize (* ptr)); 
 
 return статус;
}

Я закомментировал две строки free(ptr) и "ERROR: ..." внутри функции 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: выделено памяти:% u байтов", _ msize (input_image)); 
 else 
 printf ("\ nPoint3: Память не выделено "); 
 
} 
3
t0mm13b

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

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);
2
Bertrand Marron

В вашем исходном коде, когда вы передавали 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;
}

Вы можете вызвать вышеуказанную функцию в 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
juventus

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

Есть 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;
}

Таким образом, вы можете изменить свою ценность.

  1. таНос:

Ключевым моментом функции 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
VELVETDETH

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

    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
PeterS