I'm trying to use malloc and realloc to hold an array of structs. The array should dynamically grow, size should increase by 10 struct elements every time.
Struct:
typedef struct
{
unsigned char foreign_word_[100] = {0};
unsigned char native_word_[100] = {0};
} VocabularyCouple;
In my main, I initialize the array with malloc:
VocabularyCouple* VocStruct = (VocabularyCouple*)malloc(sizeof(*VocStruct) * 10);
Increasing the size of the struct-array seems to work fine in main...
VocabularyCouple* temp = (VocabularyCouple*)realloc(VocStruct, (sizeof(VocabularyCouple) * 20));
if (temp == NULL)
{
printf("ERROR: Out of Memory\n");
return 4;
}
else
{
VocStruct = temp;
free(temp);
temp = NULL;
}
However, if I put the realloc-part into a function like this:
uint8_t resizeVoc(uint32_t new_size, VocabularyCouple **VocStruct)
{
VocabularyCouple *temp = (VocabularyCouple*)realloc(*VocStruct, (sizeof(VocabularyCouple) * new_size));
...
}
I can only call the function once. Every other call will result in this error:
HEAP[VocTest.exe]: Invalid address specified to RtlValidateHeap( 01300000, 01308500 )
Unless I'm missing something, this should be the same problem as c - Realloc an array of Structs, but I just can't get it to work.
Thank you for your help!
VocStruct = temp;
free(temp);
This is wrong, you free all memory as soon as you have allocated it. VocStruct and temp point at the same memory area. Just remove the free().
To clarify, the temp pointer is just there in case realloc fails. Had you written VocStruct = realloc(VocStruct, ... and realloc fails, then you would have overwritten the only pointer to the allocated memory with NULL and created a memory leak. But you only ever have 1 chunk of memory - even though 2 pointers point at it at the same time.
Related
I have an array that I want to increase the size of during runtime. I assign values to the elements of the array by using a loop, and when the index of the loop hits the number of elements of the array, I want to increase the size of the array.
What I did, actually works; I can assign values to elements of the array that I would normally not be able to assign any values to without increasing the array's size. The bad side is, it gives me a crash after the program runs and finishes smoothly. What is wrong here? Is it that maybe the memory that I try to allocate for the array is already filled?
int main()
{
int arr[3];
int num_of_elements = sizeof(arr)/sizeof(arr[0]); // This gives '3', I checked
for(i = 0; i < 10; i++)
{
if(i == num_of_elements)
{
num_of_elements = num_of_elements + 10;
realloc(arr, num_of_elements);
}
arr[i] = i+10;
printf("%d\n", arr[i]);
}
return 0;
}
Well you are invoking undefined behavior. From standard ยง7.22.3.5
void *realloc(void *ptr, size_t size);
If ptr is a null pointer, the realloc function behaves like the malloc
function for the specified size. Otherwise, if ptr does not match a
pointer earlier returned by a memory management function, or if the
space has been deallocated by a call to the free or realloc function,
the behavior is undefined. If memory for the new object cannot be
allocated, the old object is not deallocated and its value is
unchanged.
By memory management function - it means malloc etc. arr is not dynamically allocated memory. So passing this to realloc is undefined behavior - in your case that behavior leads you to crash in program.
It would work if you do this
int *arr = malloc(sizeof(int)*3);
if( arr == NULL){
perror("Malloc failed");
exit(EXIT_FAILURE);
}
...
int *p = realloc(arr,num_of_elements*sizeof(int));
^^^^^
if(p == NULL ){
perror("realloc failed");
exit(EXIT_FAILURE);
}
arr = p;
Check how realloc is used.
The takeaways will be:-
Check the return value of realloc, malloc.
You were trying to reallocate extra 10 elements for which you need 10*sizeof(int) amount of memory.
Don't do arr = realloc(arr,SIZE) in case realloc fails you will have memory leak.
Why realloc to p after all you do arr=p annyway?
Two reasons so far
The answer to this is when realloc fails then it returns NULL now if you assign arr to NULL then you may have a situation where you lose the only reference to the previously allocated memory - leading to a memory leak. That's why we do it like this.
Note this from standard
The realloc function returns a pointer to the new object (which may
have the same value as a pointer to the old object), or a null pointer
if the new object could not be allocated.
Notice that may part - it might be the same address as before as pointed by arr or it might be different one. That explains why we should store it in some temporary pointer and then we assign it later.
You should have done this:
arr = realloc(arr, num_of_elements);
^^^^^
realloc() does not necessarily extend or shrink the allocated memory in-place, it invalidates the dynamic memory that its first argument points to and allocates new memory, while preserving the content of the previous memory.
One possible implementation is :
void* realloc(void* ptr, size_t size) {
void* ret = malloc(size);
if (ret == NULL) return ret;
if (ptr != NULL) {
memcpy(ret, ptr, /* previous size from system */);
free(ptr);
}
return ret;
}
In general it is difficult to understand what and why is happening.
In the beginning of the program I declare two 2D dynamic arrays (all the arrays used in the program have the same dimensions):
int **initial_array;
int **new_array;
Then I allocate the necessary memory:
//dynamic allocate arrays (1st Dimension)
initial_array = calloc(N,sizeof(int));
new_array = calloc(N,sizeof(int));
//check if the memory has been allocated correctly
if (initial_array==NULL || new_array==NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
for (i=0;i<N;i++)
{
//dynamic allocate arrays (2nd Dimension)
initial_array[i] = calloc(P, sizeof(int));
new_array[i] = calloc(P, sizeof(int));
}
I then call a function that takes the values of the initial array, generates another 2D dynamic array, which I print (inside the function) and free (by calling another function) without a problem, and I store this array to the new_array:
new_array = create_new_array(some_data, initial_array);
Then I store the values to the initial_array:
for (i=0;i<N;i++)
{
for (p=0;p<P;p++)
{
initial_array[i][p] = new_array[i][p];
}
}
free_array_in_function(new_array);
So far so good. The problem comes when I free the arrays. The initial_array works perfectly:
//free memory
for (i=0;i<N;i++)
{
free(initial_array[i]);
}
free(initial_array);
Then, I try with the new_array but the program crashes:
//free memory
for (i=0;i<N;i++)
{
free(new_array[i]);
}
free(new_array);
ERROR: Unhandled exception at 0x102d12b4 (msvcr90d.dll) in Genetic_v1.exe:
0xC0000005: Access violation reading location 0xfeeefee8.
Any ideas why is this happening?
//Function
int **create_new_array(double *some_data, int **individuals_table)
{
int **children;
//dynamic allocate array of children (1st Dimension)
children = calloc(N,sizeof(int));
//check if the memory has been allocated correctly
if (children==NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
for (cv01=0;cv01<N;cv01++)
{
//dynamic allocate array of Individuals (2nd Dimension)
children[cv01] = calloc(P, sizeof(int));
//check if the memory has been allocated correctly
if (children[cv01]==NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
}
//Do some calculations
return children;
}
Because your first allocation is wrong
initial_array = calloc(N,sizeof(int));
new_array = calloc(N,sizeof(int));
should be
initial_array = calloc(N,sizeof(int *));
new_array = calloc(N,sizeof(int *));
most likely you are trying this code on 64bit OS, otherwise it could have worked acidentally.
Also you overwrite the pointer new_array you don't need to this
new_array = calloc(N,sizeof(int));
or this inside the for loop
new_array[i] = calloc(P, sizeof(int));
since you have this
new_array = create_new_array(some_data, initial_array);
And finally comment
free_array_in_function(new_array);
because you are freeing the same pointer twice. And when you try to access the arryays in
free(initial_array[i]);
you are dereferencing a pointer that was already free'd.
That is not how pointers work, once you calloc the first time you have a pointer i.e. an integer value which represents a virtual addrees to memory, if you calloc again and assign to the previous pointer, then you overwrite the address and thus cause a memory leak.
Then you free the pointer you allocated with the create_new_array function, but you can't free the first calloced pointer since you have lost the reference to it.
sizeof(int) is not same as sizeof(int *). Even sometime it might be same depending on the platform you need to use sizeof(int *) here i.e. allocate memory to hold your pointers first.
For your
int **initial_array = calloc(N,sizeof(int *));
int **new_array = calloc(N,sizeof(int *));
Later you need to allocate memory for your pointers individually.
Now you should have :
initial_array[i] = calloc(P,sizeof(int));
In free_array_in_function(new_array)you are freeing the memory that is the reason you are
getting the error. The reason you are freeing the memory twice.
I have a global variable called exam which is of type struct Exam:
typedef struct
{
Question* phead;
}Exam;
Exam exam;
In a function I malloc space for the pointer phead:
int initExam()
{
exam.phead = malloc(sizeof(Question*));
exam.phead = NULL;
return 1;
}
In a separate function I try to free this memory:
void CleanUp()
{
unsigned int i = 0;
Question* currentQuestion = exam.phead;
while (currentQuestion != NULL) {
// some other code
}
exam.phead = NULL;
}
I have also tried the following inside my function:
free(exam.phead);
My issue is it does not seem to free the memory allocated by malloc. I would like CleanUp() to free up the memory allocated by exam.phead and I cannot change the function signatures or move the free() calls to another function. Is there something I'm doing wrong? I'm fairly new to C programming. Thanks!
You have a memory leak, right from the off:
int initExam()
{
exam.phead = malloc(sizeof(Question*));//assign address of allocated memory
exam.phead = NULL;//reassign member, to a NULL-pointer
return 1;
}
the exam.phead member is assigned the address of the memory you allocated, only to become a null-pointer right after. A null pointer can be free'd safely, but it doesn't do anything.
Meanwhile, the malloc'ed memory will stay allocated, but you have no pointer to it, and therefore cannot manage it. You can't free the memory, nor can you use it. I take it the NULL assignment is an attempt to initialize the memory to a "clean" value. There are ways to to this, which I'll get to in a moment.
Anyway, because phead is NULL, the following statements:
Question* currentQuestion = exam.phead;//is the same as currentQuestion = NULL;
while (currentQuestion != NULL) //is the same as while(0)
don't make sense, at all.
To initialize newly allocated memory, either use memset, or calloc. The latter initializes the allocated block of memory to zero, memset can do this do (calloc is basically the same as calling malloc + memset), but allows you to initialize to any value you like:
char *foo = calloc(100, sizeof *foo);// or calloc(100, 1);
//is the same as writing:
char *bar = malloc(100);
memset(bar, '\0', 100);
You're setting exam.phead in initExam to NULL right after you allocate memory with malloc. free() doesn't do anything with a NULL pointer so you're leaking memory.
I am implementing symbol table using link list, The code works fine but there is memory leak in code,
I have following structure
struct node
{
char* pcKey;
void* pvValue;
struct node *next;
};
struct _Sym
{
int totalBindings;
struct node *node;
};
add I have sym_new method to allocate memory for sym instance
sym Sym_new (void)
{
_Sym *m_SymTable_t = (_Sym*) malloc (sizeof(_Sym));
if(m_SymTable_t == NULL)
{
return NULL;
}
else
{
m_SymTable_t->totalBindings = 0;
m_SymTable_t->node = NULL;
return m_SymTable_t;
}//endif
}
I am allocating memory for key and value in other function based on the string length.
The free method is
typedef struct _Sym *Sym;
void Sym_free (Sym m_SymTable_t)
{
assert(m_SymTable_t != NULL);
struct node* temp = m_SymTable_t->node;
struct node *currentBinding = NULL;
while(temp != NULL)
{
currentBinding = temp;
temp = temp -> next;
//Removing comment for the below line throws segfault
//free(currentBinding -> pcKey);
//free(currentBinding -> pvValue);
free(currentBinding);
}
free(m_SymTable_t);
}
What is proper way to free the sym completely?
I have uploaded my symTable_Link.cpp file at link
The variables pcKey and pvValue should probably be initialised to null in the Sym_new() function. Otherwise they may contain any old value. This is because malloc doesn't necessarily zero the memory allocated: it just allocates a chunk of memory and the memory could therefore be filled with junk.
So, if for some reason sym_put() is not called for the newly created object these pointers could point to invalid memory and upon your call to free() segfault. If you initialise them to null free() will just ignore them and won't try to free the memory.
A "hacky" DEBUG-only technique you could use to check that the pcKey and pvValue variables are definitely allocated by a sym_put call would be to initialise them in sym_new with a dummy value, for example 0xCDCDCDCD (careful about pointer-widths here... this is why I'm calling this a hacky technique). Then in sym_free check for this magic constant before freeing pcKey and pvValue. If you find it, there's the problem...
Also of interest may be the thread Do I cast the result of malloc?
EDIT:
Looked at the code linked and you appear to be discarding const!
The function id defined as:
int SymTable_put (SymTable_t m_SymTable_t, const char *pcKey, const void *pvValue)
But then does this cast...
temp->pcKey = (char*)pcKey;
temp->pvValue = (char*)pvValue;
This is a bad idea. You're "fooling" the compiler into invalidating your const promise.
THE BUG:
Ok, so you allocate as follows
temp->pcKey = (char*) malloc (sizeof(char) * strlen (pcKey));
But then you overwrite this pointer using
temp->pcKey = (char*)pcKey;
So you a) have a memory leak and b) have just stashed the wrong pointer, which is probs why you get the segfault. You you probably meant to do instead is (strdup is useful here)...
temp->pcKey = strdup(pcKey);
This will allocate new memory for the string in pcKey and COPY the string into the new memory.
I would hazzard a guess you called the function like this...
SymTable_put (xxx, "KEY string", "VALUE string");
Then your code did this
temp->pcKey = (char*)malloc (sizeof(char) * strlen (pcKey));
...
temp->pcKey = (char*)pcKey;
So now temp->pcKey points to "KEY string" itself and not a copy of it. So when you try to free the string constant, your program complains. What you want to do is copy the string from pcKey into temp->pcKey instead of overwriting the pointer.
EDIT:
As per comments the mallocs need space + 1 to include the null terminator. Also sizeof(char) is always 1, so is redundant. Try strdup instread.
why this,causes a segfault??
#include<stdio.h>
#include<stdlib.h>
struct node
{
double d;
int *array;
char c;
};
void allocator(struct node *ptr)
{
int *tmp;
tmp = (int*)realloc(ptr, 10);
if(!tmp)
{
ptr->array=tmp;
ptr->array[0] = 23;
}
}
int
main()
{
struct node *ptr = (struct node*)malloc(sizeof(struct node));
ptr->c = 'y';
allocator(ptr);
printf(" %c\n", ptr->c);
printf(" %d\n", ptr->array[0]);
return 0;
}
i got an impression as if the realloc() in the allocator function allocates memory which also maps to the memory allocated by malloc() in the main..
but how does this could happen?? Doesn't the memory manager(i guess the lib(stdlib) here) keeps track of free and allocated spaces in a process??
You're allocating space enough for a struct node then reallocating it to 10 bytes, then accessing the member c which, due to the structure of node, is probably past the 10th byte. This causes a segfault.
Also, if whoever's business it is to decide decides that it needs to move the memory block, realloc returns a pointer to the new location but the pointer back in main still points to the old block which has been reclaimed. This could also cause a segfault.
Also, in this code:
int *tmp;
tmp = (int*)realloc(ptr, 10);
if(!tmp)
{
ptr->array=tmp;
ptr->array[0] = 23;
}
if !tmp, you're accessing a NULL pointer because you're assigning tmp to ptr->array then accessing the 0th element. This could also cause a segfault.
There are many problems in your code. You may need to rewrite much of it.
The problem with this is the attempt to access an unallocated pointer, which happens in main:
printf(" %d\n", ptr->array[0]);
Your allocation function assigns space for ptr, which is a structure, but not for the array within that structure. Possibly this is not what you intended to do (comment your code!).