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?
4 Answers 4
that memory can only be referenced by formal argument
fPtrand not the actual argument(let's call itaPtr).
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!
1 Comment
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
int* ptr = (int*)NULL;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?malloc() statement. Although some are saying that casting is no longer bad based on the comments on the link.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
free on the pointer(void**)&ptr - accessing int * via *(void**) is undefined behavior.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
MACRO why not inline function instead?inline is for a function. NEW_ARRAY(ptr, n) does not act like a function, more like ptr = foo(n, typeof ptr).
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?assign a memory block- a pointer is not a memory block, it's just an address to the memory.int *fPtrwithint **fPtrto receive&aPtras argument?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 inmain()(and is essentially a memory-leak). Call withdynamAlloc (&pointer)inmain().*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!