Как динамически распределить память в функции? - PullRequest
0 голосов
/ 26 января 2020

Скажем, я хочу динамически распределять память, но с функцией вместо функции main ().

Итак, я попытался сделать это:

dynamAlloc(int *fPtr)
{
   fPtr=malloc(cols * sizeof(*fPtr) );
   if(fPtr==NULL)
    { 
      printf("Can't allocate memory");
      exit(1);
    }
}

Тогда я понял: даже хотя память, выделенная в куче, доступна на время жизни программы, на эту память можно ссылаться только с помощью формального аргумента fPtr, а не фактического аргумента (назовем его aPtr). Но как только функция завершается, эта память теряется.

Так как же тогда динамически распределять память с помощью функции?

Ответы [ 4 ]

2 голосов
/ 26 января 2020

что на память можно ссылаться только формальным аргументом fPtr, а не фактическим аргументом (назовем его aPtr).

aPtr не может обозначать кучи памяти объект перед вызовом dynamAlloc(), поскольку объект еще не выделен, а его адрес назначен aPtr через fPtr. После этого aPtr do ссылается на объект кучи.

Нам просто нужно передать адрес указателя aPtr в dynamAlloc(). Таким образом, вам нужны соответствующие аргументы (фактические аргументы) и параметры (формальные аргументы) для передачи адреса указателя aPtr между функциями, как вы видите ниже.

Так как же тогда динамически распределять память с функцией?

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

#include <stdio.h>
#include <stdlib.h>

#define cols 5

void dynamAlloc(int** fPtr);

int main()
{
    int* aPtr;

    dynamAlloc(&aPtr);

    free(aPtr);

    return 0;
}


void dynamAlloc(int** fPtr)                 
{
   *fPtr = malloc(sizeof(*fPtr) * cols);
   if(*fPtr == NULL)
    { 
      printf("Can't allocate memory");
      exit(1);
    }
}

Не забудьте free() память кучи!

1 голос
/ 26 января 2020

или просто сделайте так:

void dynamAlloc(int **fPtr)
{
   *fPtr=malloc(cols * sizeof(**fPtr) ); // malloc is returning void* so in that place it would be compiler error, so pointer returned from malloc should be casted to the pointer type of the value.
   if(*fPtr==NULL) // that would be a warning in gcc since NULL is a macro eq to 0, or (void*)0, it compiler version
    { 
      printf("Can't allocate memory");
      exit(1);
    }
}

и использование функции:

int* ptr = (int*)NULL;
dynamAlloc(&ptr);
*ptr = 1; // assign 1 to the first element, ptr is a valid pointer here

, но синтаксис двойного указателя может оказаться медленным в некоторых условиях, ответьте с возвратом в end od fucntion, копия этого локального указателя - лучшая практика.

0 голосов
/ 26 января 2020

Так как вам нужно изменить сам указатель - нужен указатель на указатель

void *allocate(void **tmp, size_t size)
{
    if(tmp)
    {
        *tmp = malloc(size);
    }
    return *tmp;
}


int main()
{
    int *ptr;

    if(!allocate((void**)&ptr, sizeof(*ptr) * 100))
    {
        perror("Error\n");
        exit(1);
    }
    /* do something*/
    free(ptr);
}
0 голосов
/ 26 января 2020

Удобнее использовать функцию макроса, например:

#include <stdio.h>
#include <stdlib.h>

#define NEW_ARRAY(ptr, n) \
    { \
        (ptr) = malloc((size_t) (n) * sizeof (ptr)[0]); \
        if ((ptr) == NULL) { \
            fputs("Can't allocate memory\n", stderr); \
            exit(EXIT_FAILURE); \
        } \
    }

#define NEW(ptr) NEW_ARRAY((ptr), 1)

int main(void)
{
    int *myArray;
    const int myArrayLen = 100;
    int i;

    NEW_ARRAY(myArray, myArrayLen);
    for (i = 0; i < myArrayLen; i++) {
        /*...*/
    }
    return 0;
}

Обновление:

Цель макроса - абстрагировать детали и сделать выделение памяти менее подверженным ошибкам , С (не макро) функцией мы должны были бы передать размер элемента в качестве параметра, поскольку эта информация теряется, когда указатель передается формальному параметру типа void pointer:

void NewArray(void *ptr, int n, int elemSize)
{
        *ptr = malloc((size_t) n * sizeof elemSize);
        if (*ptr == NULL) {
            fputs("Can't allocate memory\n", stderr);
            exit(EXIT_FAILURE);
        }
}

С функцией NewArray вызов выделения, соответствующий первому примеру, становится

NewArray(&myArray, n, sizeof myArray[0]);

, что нас мало покупает.

...