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?
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!
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.
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);
}
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.
Related
I'm trying to reallocate memory for an pointers vector, originally the vector is:
Album* albuns
Where Album is a struct;
I created a function passing the adress of type albuns and the total number of albuns as arguments:
void AddAlbum (int* n_albuns, Album** albuns);
I wanted to reallocate memory for albuns so it could receive another pointer to album, so i did:
int aux = (*n_albuns) + 1;
albuns = (Album**) realloc (albuns,(sizeof(Album*) * aux));
albuns[*n_albuns] = (Album*) malloc (sizeof(Album));
(*n_albuns)++;
but the function returns me a SegFault in this line:
albuns[*n_albuns] = (Album*) malloc (sizeof(Album));
Any ideias? I'm relatively new to memory allocation
There are several issues with the question code. See impeded comments.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Question code should include a model of the structure. */
typedef struct Album_s
{
int a;
char b;
int *c;
char *d;
struct Album_s *e;
} Album;
/* Question indicates: void AddAlbum (int* n_albuns, Album** albuns);
** However, in order to change the size of the array, the address of the
** array must be supplied. Hence, the change from **albuns to ***albuns.
*/
int AddAlbum(int *n_albuns, Album ***albums)
{
int rCode = EXIT_SUCCESS;
void *newMem = NULL;
/* Attempt to increase the size of the array by one (pointer) element.
** The question code casts (Album**) the value returned by realloc(),
** which is not necessary. It is also important to verify that the call
** to realloc() actually succeeded. The realloc code below is fairly
** customary in order to check for this.
*/
newMem = realloc(*albums, sizeof(Album *) * (*n_albuns + 1));
if(!newMem)
{
rCode=errno;
goto CLEANUP;
}
*albums = newMem;
/* Again, the question code casts (Album*) the value returned by malloc(),
** which is not necessary. Being that the albums parameter is a pointer
** to a pointer to a pointer, the following assignment is correct. Again,
** it is important to verify that the call to malloc() actually succeeded.
*/
(*albums)[*n_albuns] = malloc(sizeof(Album));
if(!(*albums)[*n_albuns])
{
rCode=errno;
goto CLEANUP;
}
(*n_albuns)++;
CLEANUP:
return(rCode);
}
/* Example of how AddAlbum() might be called. */
int main(void)
{
int rCode = EXIT_SUCCESS;
Album **albunArray = NULL;
int albunCnt = 0;
int desiredCnt = 10;
while(albunCnt < desiredCnt)
{
rCode=AddAlbum(&albunCnt, &albunArray);
if(rCode)
{
fprintf(stderr, "AddAlbum() failed. errno: %d \"%s\"\n", rCode, strerror(rCode));
goto CLEANUP;
}
printf("Array element %d of %d added.\n", albunCnt, desiredCnt);
}
CLEANUP:
return(rCode);
}
Here is basically what I'm trying to do:
free memory that was allocated in a different scope using double pointers.
The following code is incomplete but fully describes what I'm trying to perform.
so here is my function to read the buffer (C pseudo code)
char *read_buffer(char *buf, myStruct **arr, int nbElm)
{
buf = malloc(...);
...//many things done (use of the read(),close()... functions
...//but not referencing any of the buffer to my structure
...
*arr = (myStruct *) = malloc(sizeof(myStruct) * nbElm);
return (buf);
}
Here is the kind of function I use between my memory allocation and my freeing attempt:
void using_struct(myStruct *ar, int nbElm)
{
int i;
i = 0;
while (i < nbElm)
{
// Here I use my struct with no problems
// I can even retrieve its datas in the main scope
// not memory is allocated to it.
}
}
my main function :
int main(void)
{
char *buf;
myStruct *arStruct;
int nbElm = 4;
buf = read_buffer(buf, &arStruct, nbElm);
using_struct(arStruct, nbElm);
free(buf);
buf = NULL;
free(arStruct);
while(1)
{;}
return (1);
}
The only problem is either I place my while loop before or after my free function, I can't see any memory change using top
on my terminal.
Is this normal?
Thanks in advance,
You always must have exactly same number of calls to free as a calls to malloc.
myStruct **arr;
*arr = malloc(sizeof(myStruct) * nbElm);
This means you need single call to free first nbElm structs:
free(arr);
I want to create a new intarr_t with initial size len, but I've never handled this type of problem with a typedef'ed variable.
My problem is that intarr_create() should allocate the array space and then return a pointer to it if malloc was successful or a pointer to NULL if I failed. How can I fix this?
Also, why there is a * symbol in the function?
Here's my code:
#include <stdio.h>
typedef struct {
int* data;
unsigned int len;
} intarr_t;
intarr_t* intarr_create(unsigned int len) {
//intarr_t with initial size len
intarr_t = (int *) malloc(len); // not working here, can someone explain why?
if(intarr_t != NULL) {
return intarr_t;
} else {
return NULL;
}
}
int main() {
int len = 15;
int h = intarr_create(len);
printf("%d\n", h);
return 0;
}
It's not working because you did not give your variable a name. Also, int* and intarr_t are not the same type, so you will get a type mismatch unless you change the cast.
Rewrite your function into this:
intarr_t* intarr_create(unsigned int len)
{
intarr_t *result;
result = (intarr_t *)malloc(sizeof(intarr_t)); // allocate memory for struct
if(result != NULL)
{
result->data = (int *)malloc(len * sizeof(int)); // allocate memory for data
result->len = len;
if (result->data == NULL)
{
/* handle error */
}
}
else
{
/* handle error */
}
return (result);
}
You have to do a "double" malloc to get it right. First you have to allocate the memory for the intarr_t and if that was successful you have to allocate the memory for the data array.
Additionally malloc returns a void * which must be cast to the correct pointer type (should be a warning or maybe even an error with some compilers).
You have a few problems with your intarr_create function. First of all, you need to name your intarr_t variable. Now you have the slightly trickier problem of allocating memory for the actual array of integers in addition to your intarr structure. Remember, that you will have to call delete twice to destroy this object. Once on the data, and once on the actual structure itself.
intarr_t* intarr_create(unsigned int len)
{
intarr_t* array = (intarr_t*)malloc(sizeof(intarr_t));
array->data = (int*)malloc(len * sizeof(int));
return array;
}
I'm new in StackOverflow. I'm learning C pointer now.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int alloc(int* p){
p = (int*) malloc (sizeof(int));
if(!p){
puts("fail\n");
return 0;
}
*p = 4;
printf("%d\n",*p);
return 1;
}
int main(){
int* pointer;
if(!alloc(pointer)){
return -1;
}else{
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
I compile with: gcc -o main main.c
error: free(): invalid pointer: 0xb77ac000 ***
what's wrong with my code?
Arguments in C are always passed by value. So, when you call alloc(pointer), you just pass in whatever garbage value pointer contains. Inside the function, the assignment p = (int*)... only modifies the local variable/argument p. Instead, you need to pass the address of pointer into alloc, like so:
int alloc(int **p) {
*p = malloc(sizeof(int)); // side note - notice the lack of a cast
...
**p = 4; // <---- notice the double indirection here
printf("%d\n", **p); // <---- same here
return 1;
}
In main, you would call alloc like this:
if (!(alloc(&pointer))) {
....
Then, your code will work.
Everything in C is pass-by-value. This means that functions always operate on their own local copy of what you pass in to the function. Usually pointers are a good way to mimic a pass-by-reference scheme because a pointer and a copy of that pointer both contain the same memory address. In other words, a pointer and its copy both point to the same space.
In your code the issue is that the function alloc gets its own local copy of the pointer you're passing in. So when you do p = (int*) malloc (sizeof(int)); you're changing the value of p to be a new memory address, but the value of pointer in main remains unchanged.
You can get around this by passing a pointer-to-a-pointer, or by returning the new value of p.
You have two major problems in your code.
First, the alloc function creates a pointer via malloc, but never frees it, nor does it return the pointer to the calling function. This guarantees the memory the pointer addresses can never be freed up via the free command, and you now have memory leaks.
Second, the variable, int* pointer in main, is not being modified as you would think. In C, function arguments are "passed by value". You have two ways to address this problem:
Pass a pointer to the variable you want to modify (in your case, a pointer to a pointer to an int)
Have the function return the pointer to the function that called it.
Here are two implementations of my recommendations:
Approach 1
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p);
int alloc(int** p) {
if (!p) {
printf("Invalid argument\n");
return (-1);
}
if ((*p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (-1);
}
**p = 123;
printf("p:%p - *p:%p - **p:%d\n", p, *p, **p);
return 0;
}
int main(){
int* pointer;
if(alloc(&pointer) != 0){
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
return 0;
}
Sample Run for Approach 1
p:0xbfbea07c - *p:0x8656008 - **p:123
&pointer:0xbfbea07cointer - pointer:0x8656008ointer - *pointer:123
Approach 2
#include <stdio.h>
#include <stdlib.h>
int* alloc(void) {
int* p;
if ((p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (NULL);
}
*p = 123;
printf("p:%p - *p:%d\n", p, *p);
return p;
}
int main(){
int* pointer = alloc();
if(pointer == NULL) {
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
pointer = NULL;
return 0;
}
Sample Run for Approach 2
p:0x858e008 - *p:123
&pointer:0xbf9bb1ac- pointer:0x858e008- *pointer:123
You are passing the pointer by value into your alloc function. Although that function takes a pointer to an int, that pointer itself cannot be modified by the function. If you make alloc accept **p, set *p = ..., and pass in &pointer from main, it should work.
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p){
*p = (int*) malloc (sizeof(int));
if(!*p){
puts("fail\n");
return 0;
}
**p = 4;
printf("%d\n",**p);
return 1;
}
int main() {
int* pointer;
if(!alloc(&pointer)){
return -1;
} else {
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
If you want a function to write to a non-array parameter of type T, you must pass a pointer to that parameter.
void func( T *ptr )
{
*ptr = new_value;
}
void foo ( void )
{
T var;
func( &var ); // writes new value to var
}
If T is a pointer type Q *, it would look like
void func( Q **ptr )
{
*ptr = new_pointer_value;
}
void foo ( void )
{
Q *var;
func( &var ); // writes new pointer value to var
}
If Q is a pointer type R *, you would get
void func( R ***ptr )
{
*ptr = new_pointer_to_pointer_value;
}
void foo ( void )
{
R **var;
func( &var ); // writes new pointer to pointer value to var
}
The pattern is the same in all three cases; you're passing the address of the variable var, so the formal parameter ptr has to have one more level of indirection than the actual parameter var.
One sylistic nit: instead of writing
p = (int *) malloc( sizeof (int) );
use
p = malloc( sizeof *p );
instead.
In C (as of the 1989 standard), you don't need to cast the result of malloc; void pointers can be assigned to other pointer types and vice versa without needing a cast (this is not true in C++, but if you're writing C++, you should be using the new operator instead of malloc anyway). Also, under the 1989 version of the language, using the cast would mask a bug if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope. That hasn't been a problem since the 1999 version, though, so now it's more a matter of readability than anything else.
The type of the expression *p is int, so the result of sizeof *p is the same as the result of sizeof (int). This way, if you ever change the type of p, you don't have to modify the malloc call.
To allocate an array of values, you'd use something like
T *p = malloc( sizeof *p * NUM_ELEMENTS );
or, if you want everything to be zeroed out initially, use
T *p = calloc( sizeof *p, NUM_ELEMENTS );
This is one of those annoying things where you know the answer is easy, but you just can't see it.
The printf statement in AllocIntArray shows that arrayPtr is correctly being assigned a memory location, however when the printf statement in main is run, it shows arrayB is still set to NULL.
Can someone show me what I am doing wrong when passing in arrayB to AllocIntArray?
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int *arrayPtr, int numElements);
int main()
{
int *arrayB = NULL;
AllocIntArray(arrayB, 10);
printf("Pointer: %p\n", arrayB);
free(arrayB);
getchar();
return EXIT_SUCCESS;
}
void AllocIntArray(int *arrayPtr, int numElements)
{
arrayPtr = (int *)malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", arrayPtr);
if(arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
}
Pass the double pointer.
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int **arrayPtr, int numElements);
int main()
{
int *arrayB = NULL;
AllocIntArray(&arrayB, 10);
printf("Pointer: %p\n", arrayB);
free(arrayB);
getchar();
return EXIT_SUCCESS;
}
void AllocIntArray(int **arrayPtr, int numElements)
{
*arrayPtr = malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", *arrayPtr);
if(*arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
}
That's because arrayB is passed to AllocIntArray by value. Either pass it by reference (with a pointer-to-pointer), or better, return it from AllocIntArray:
int *AllocIntArray(int numElements)
{
int *arrayPtr = malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", arrayPtr);
if(arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
return arrayPtr;
}
You need to brush up a bit on parameter passing to functions.
The pointer you are sending to AllocIntArray is being copied into arrayPtr, The line
arrayPtr = (int *)malloc(sizeof(int) * numElements);
assigns a value into the copy, and not the original variable, and therefore the original variable still points to nowhere.
First solution that comes to mind is to send a pointer to that pointer, but I think you'd best do some general brushing up on the matter of parameter passing before going much further.
arrayPtr is a pointer and the pointer is passed by value to the parameter. AllocIntArray can modify its version of arrayPtr but the changes won't be seen by main().
(Edit: if you're using C++) modifying the signature for AllocIntArray to change the type of arrayPtr to a reference ought to fix your problem.
void AllocIntArray(int *&arrayPtr, int numElements)
The basic problem here is you are passing arrayB to AllocIntArray function as passed by value .In AllocIntArray its allocating memory properly and arrayptr is valid but in main function its not the same memory which you are expecting .
This is the basic C programming concept and you can check bu adding print in both the function .
EX: I am sharing the difference between both problem and success case with below example .
/*Code with passed by value as a parameter*/
#include<stdio.h>
#include<stdlib.h>
void AllocateIntarray(int *arrayptr,int numElements)
{
arrayptr = (int*) malloc(sizeof(int)*numElements);
printf("Inside _func_AllocateIntarray_pointer:%p\n",arrayptr);
if(arrayptr == NULL)
{
printf("ERR_MEM_ALLOCATION_FAILED:\n");
}
}
int main()
{
int *arrayB = NULL;
AllocateIntarray(arrayB,10);
printf("Inside _func_mainPointer:%p\n",arrayB);
free(arrayB);
return 0;
}
/*Output :
Inside _func_AllocateIntarray_pointer:0x55be51f96260
Inside _func_mainPointer:(nil)*/
Code with Passed by reference and using double pointer .
#include<stdio.h>
#include<stdlib.h>
void AllocateIntarray(int **arrayptr,int numElements)
{
*arrayptr = malloc(sizeof(int)*numElements);
printf("Inside _func_AllocateIntarray_pointer:%p\n",*arrayptr);
if(*arrayptr == NULL)
{
printf("ERR_MEM_ALLOCATION_FAILED:\n");
}
}
int main()
{
int *arrayB = NULL;
AllocateIntarray(&arrayB,10);
printf("Inside _func_mainPointer:%p\n",arrayB);
free(arrayB);
return 0;
}
/*Output :
Inside _func_AllocateIntarray_pointer:0x562bacd1f260
Inside _func_mainPointer:0x562bacd1f260*/