1

Say I want to dynamically allocate memory but with a function instead of in the main() function.

So I tried to do this:

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

Then I realised: Even though memory allocated on the heap is available for the lifetime of program, that memory can only be referenced by formal argument fPtr and not the actual argument(let's call it aPtr). But once, function is exited, that memory is lost.

So how then do I dynamically allocate memory with a function?

6
  • formal arument fPtr and not the actual argumen - what is a "formal argument"? what is an "actual argument"? How do they differ? Are you asking how to assign a value to a variable from outer scope from a function? Commented Jan 26, 2020 at 7:28
  • 1
    So something like How to change a variable in a calling function from a called function?? assign a memory block - a pointer is not a memory block, it's just an address to the memory. Commented Jan 26, 2020 at 7:40
  • 1
    So all I have to do is replace int *fPtr with int **fPtr to receive &aPtr as argument? Commented Jan 26, 2020 at 7:56
  • 4
    dynamAlloc(int **fPtr) and then *fPtr=malloc(cols * sizeof(**fPtr) ); Otherwise you are assigning the allocated block to a copy of the pointer that is local to the function so the allocation is never seen back in main() (and is essentially a memory-leak). Call with dynamAlloc (&pointer) in main(). Commented Jan 26, 2020 at 7:56
  • 1
    @KamiCuk @DavidThe multiple dereferencing * operaters made it look harder than it actually is but I realised the concept is still the same. Much thanks for showing me the way! Commented Jan 26, 2020 at 8:04

4 Answers 4

2

that memory can only be referenced by formal argument fPtr and not the actual argument(let's call it aPtr).

aPtr cannot denote to the heap memory object before the call to dynamAlloc() because the object has not been allocated yet and its address assigned to aPtr trough fPtr. Thereafter aPtr do reference the heap object.

We just need to pass the address of the pointer of aPtr to dynamAlloc(). So you need appropriate arguments(actual arguments) and parameters (formal arguments) to pass the address of the pointer aPtr between the functions, like you see below.

So how then do I dynamically allocate memory with a function?

You do it like you do it main(), doesn´t matter if the pointer was declared inside of main() or another function, you just need to pass the address of the pointer aPtr to the other functions, in which you want to use the heap memory object, like f.e.:

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

Do not forget to free() the heap memory!

Sign up to request clarification or add additional context in comments.

1 Comment

it will remain untouched in memory after the program is terminated . Won't the OS claim back all the allocated memory to a program?
1

or just make it like this:

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

and the fuction usage:

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

but double pointer syntax can turn out slow in some conditions, answer with return in the end od fucntion, copy of that local pointer is better practise.

5 Comments

as C is required it can be done like that int* ptr = (int*)NULL;
you function depends on global variables. Do not exit the program in such a functions.
that is not mine fuction, this is not a case to fix it, as embedded firmware engineer I would make many other changes to that code, starting with that the function in this case is waste of processor time, unless your doing kind of wrapper to that malloc that can check for the leaked bytes later, bus still, better choice is to make that wrapper online-with macro.
@JohnySiemanoKolano so you are saying that int* dynamAlloc(int * fPtr) is faster(i guess that's better?), ie, returning address in heap is better than double pointer syntax? Any reason why one would use double pointer syntax over thr other?
Also, I have read that casting return value of malloc is bad practice. See stackoverflow.com/q/605845/10701114. That's why I didn't cast mine as opposed to your comment following the malloc() statement. Although some are saying that casting is no longer bad based on the comments on the link.
0

As you need to change the pointer itself - pointer to pointer is needed

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

2 Comments

@TruthSeeker extremely complicated way. free on the pointer
(void**)&ptr - accessing int * via *(void**) is undefined behavior.
0

It's more convenient to use a macro function, like this:

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

Update:

The purpose of the macro is to abstract away the details and make memory allocation less error prone. With a (non-macro) function we would have to pass the element size as a parameter as that information is lost when a pointer is passed to a formal parameter of type 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);
        }
}

With the function NewArray the allocation call corresponding to the first example becomes

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

which doesn't buy us much.

4 Comments

why MACRO why not inline function instead?
@TruthSeeker inline is for a function. NEW_ARRAY(ptr, n) does not act like a function, more like ptr = foo(n, typeof ptr).
@chux-ReinstateMonica: yes, that's true. The point I was making is when we can solve through regular function why to use MACRO's. After reading this. I try to avoid MACRO's wherever it is possible.
@TruthSeeker Then better to state your point (your want to express something) than ask a question (sounds like you want to learn something)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.