what will be the result if i reallocating the calloc pointer? - c

int main()
{
int *ptr = (int*)calloc(10,sizeof(int));//allocating memory for 10 integers
ptr = realloc(ptr,20*sizeof(int)); //reallocating the memory for 20 integers
free(ptr);
return 0;
}
Initially the ptr hold memory contains zeros,but the newly created memory contains zeros or garbage values.
If zeros present how can realloc know weather the ptr is created using malloc or calloc.

Even if you called realloc properly like (without casting the result and assigning it back or it doesn't work properly):
ptr = realloc(ptr,20*sizeof(int));
(and some may say that it's not safe as realloc can return NULL thus losing the ref to ptr)
it doesn't. It just reallocates without setting the rest to 0
You have to set the rest of the memory to 0 manually using memset for instance.
I would do:
int *ptr_new = realloc(ptr,20*sizeof(int));
if (ptr_new == NULL) { /* print error, free(ptr) and exit: no more memory */ }
else
{
// set the end of memory to 0
memset(ptr_new+10,0,sizeof(int)*10);
...
Note: a common mistake is not assigning back the result of realloc since it seems to work, up to the point where the OS needs to move the memory to another block, in that case your ptr pointer becomes invalid and you have undefined behaviour.

Related

Using 'realloc()' during runtime gives crash, why? - C Language

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

C - using realloc on pointer to pointer result in segmentation fault

I am trying to use realloc since i want to improve speed in my code. When a certain condition is fulfilled, I want to realloc a void double pointer to a larger size, but I get a segmentation fault. Here is the code.
if (p_bheap->currentSize == p_bheap->arraySize){
p_bheap->arraySize = p_bheap->arraySize*2 + 1;
p_bheap->pp_array = realloc(p_bheap->pp_array, p_bheap->arraySize);
}
This however results in a segmentation fault. If I however make my own reallocating function it works.
if (p_bheap->currentSize == p_bheap->arraySize){
p_bheap->pp_array = bheap_reallocate(p_bheap);
}
void** bheap_reallocate(bheap* p_bheap){
p_bheap->arraySize = p_bheap->arraySize*2 + 1;
void** pp_newArray = malloc(p_bheap->arraySize*sizeof(void*));
for (int i = 0; i < p_bheap->currentSize; i++){
pp_newArray[i] = p_bheap->pp_array[i];
}
free(p_bheap->pp_array);
return pp_newArray;
}
Is there any clear errors that can be spotted that I have failed to see? And for those wondering I am programming a binary heap.
If you have a previously allocated object, say str and want to adjust its memory to another size, use a temporary variable to prevent memory loss in the event realloc fails. Illustration:
char *str = calloc(20, 1);
if(str) // should always check return of calls to [c][m][re]alloc.
{ // at this point, str owns 20 bytes of memory. If you use str in a subsequent
// call to realloc, and the call fails, then the memory previously allocated in
// the original call to calloc() will be lost. (memory leak).
....
char *tmp = {0};//So instead, use a temporary variable to accept memory
//and provide a way to recover if allocation fails
tmp = realloc(str, 40);//newsize (40) in bytes
if(!tmp) //test reallocation
{
//reallocation failed.
//free previously allocated memory, and decide how to proceed.
//In this case, return a NULL, and let the calling function decide.
free(str);//if allocation fails, free the previous object and leave
return NULL;
}
//reallocation succeeded. Proceed normally
str = tmp;//reallocation succeeded, assign its address to str and proceed normally
You can't use the same memory space to receive the result. Try to use a temporary array or to allocate another space.

Use of "calloc" & "realloc"

Practice
#include <stdio.h>
#include <stdlib.h>
int main(void){
int i=0,z=2;
char *p=(char *)calloc(z,(sizeof(char)));
if(!(p)){
printf("\nMemory NOT Enough\n");
goto END;
}
*p='V';
z+=2;
p=realloc(p,z*(sizeof(char))); ----A
*(p+3)='S';
for(i=0;i<z;++i)
printf("\n%d\n",p[i]);
END:free(p);p=NULL;
return 0;
}
As you can see, the line marked by A uses realloc.
In line A the p on the LHS of the = is assigned the new address generated by realloc(p,z*(sizeof(char)));.
My question is :
What happens to the previously stored address in p? Previously stored address is replaced, so does it lead to memory leak?
If the return value from realloc() is not NULL all is well;
if realloc() returns NULL you have a memory leak.
You need to use a helper variable to use realloc() safely.
char *tmp;
tmp = realloc(p, z);
if (tmp == NULL) {
fprintf(stderr, "Unable to realloc.\n");
// p still points to the old memory and its contents are valid
exit(EXIT_FAILURE); // or some other error recovery
} else {
// tmp points to a (possibly new) block of memory with the same contents
// as what p used to point to (to the maximum of the old size and z)
// p (very probably) points to an invalid address
p = tmp; // now p points to a valid address (also tmp)
// ignore tmp for now on
}
No that memory is taken care by realloc if the realloc finds sufficient memory adjascent to p then its okay else realloc moves memory to new location.note that it moves it, so old memory is freed.
realloc will attempt for the extension of the available memory range only when sufficient memory is available in the heap.
From the C standard:
size == 0
realloc might free old and return 0
alternatively realloc behaves as for size != 0 but cannot return 0
size != 0
realloc might return 0. old is not touched
if the block pointed to by old is >= size, realloc might return old
alternatively realloc allocates a block >= size, copies all bytes from old up to size, frees old and returns this new block

Understanding realloc() in C

In this example from: http://www.cplusplus.com/reference/cstdlib/realloc/
why are there two pointers: numbers and more_numbers? Can I use:
numbers = (int*) realloc (numbers, count * sizeof(int));
if (numbers!=NULL) {
numbers[count-1]=input;
}
else {
free (numbers);
puts ("Error (re)allocating memory");
exit (1);
}
The reason that example appears a little extended is to adequately deal with a failure to realloc.
numbers = (int*) realloc (numbers, count * sizeof(int));
if (numbers!=NULL) {
numbers[count-1]=input;
}
else {
free (numbers);
This will not work in the error condition; you'll be trying to free a value which you just confirmed is NULL, which probably isn't what you intend. Additionally, you've lost the (still valid) original pointer in this case (the purpose of the more_numbers pointer in your example), losing access to the data you have there and losing the ability to release the buffer.
To see why your version is wrong, you need to realise what realloc does. It does one of two things: If there is enough memory, it will return a new pointer and the old one becomes invalid. If there isn't enough memory, it will return NULL and the old pointer stays valid and unchanged.
You must store the result of realloc into a temporary variable, and not overwrite the old pointer. The reason is that if realloc returns NULL, and you overwrote the old pointer with NULL, you lost access to your existing data. So the correct way is:
int* tmp = (int*) realloc (numbers, count * sizeof(int));
if (tmp!=NULL) {
// realloc was successful. The old value of numbers is now rubbish.
// Store the result of realloc into numbers and continue.
numbers = tmp;
numbers[count-1]=input;
}
else {
// realloc failed. The old value of numbers is unchanged but doesn't have enough
// space to store input. You need to handle the error somehow.
free (numbers);
puts ("Error (re)allocating memory");
exit (1);
}
If you had stored the realloc () result directly into numbers, the "else" branch wouldn't know the old value of numbers anymore and couldn't free that memory.
According to link http://www.cplusplus.com/reference/cstdlib/realloc/
it is written "The program prompts the user for numbers until a zero character is entered. Each time a new value is introduced the memory block pointed by numbers is increased by the size of an int."
have a look at the function realloc() in http://www.tutorialspoint.com/c_standard_library/c_function_realloc.htm
void *realloc(void *ptr, size_t size);
The function returns a pointer to the newly allocated memory, or NULL if the request fails.
ptr -- This is the pointer to a memory block previously allocated with malloc, calloc or realloc to be reallocated.If this is NULL, a new block is allocated and a pointer to it is returned by the function
size -- This is the new size for the memory block, in bytes.If it is 0 and ptr points to an existing block of memory, the memory block pointed by ptr is de-allocated and a NULL pointer is returned
So after allocating memory this function returns a void pointer and it is type-casted to an integer pointer to use in the code. So each time a code is entered the memory allocated will be incremented 1 times by the sizeof(int) and the value is stored in that area.
more_numbers is the pointer which points to the starting address of the location of the memory allocated by the realloc()
numbers is the pointer which points to the array where the inputs are stored
In case if the memory allocation fails the entire memory is de-allocated using free();
You could use a function (hope i did this right):
/// int*-argument passed by-pointer
bool Enlarge(int** input, size_t new_count, int new_val)
{
void* numbers = NULL; // local ptr
numbers = (int*) realloc (*input, new_count*sizeof(int));
if (numbers!=NULL) {
*input = (int*)numbers;
(*input)[new_count - 1] = new_val;
return true;
} else {
return false;
}
}
Use it:
int* old = (int*)malloc(sizeof(int)*2);
if (!old)
return -1;
old[0] = 11; old[1] = 22;
if (!Enlarge(&old,3,33))
{
free(old);
return -2;
}
printf("A: %d, B: %d, C: %d\n", old[0], old[1], old[2]);
if (old) { free(old); }
Just beware to pass the ptr as int** and not as int* (e.g. when specifying &old[0] instead of &old.

Proper usage of realloc()

From man realloc:The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails.
So in this code snippet:
ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){ //reallocated pointer ptr1
printf("Exiting!!\n");
free(ptr);
exit(0);
}else{
free(ptr); //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
ptr = ptr1; //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address
}
Is it sufficient to just assume that the reallocated pointer points to a different block of memeory and not to the same block.Because if the assumption becomes false and realloc returns the address of the original memory block pointed to by ptr and then free(ptr) executes(for the reason given in the comments) then the memory block would be erased and the program would go nuts.
Should I put in another condition which will compare the equality of ptr and ptr1 and exclude the execution of the free(ptr) statement?
Just don't call free() on your original ptr in the happy path. Essentially realloc() has done that for you.
ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{
printf("\nExiting!!");
free(ptr);
exit(0);
}
else
{
ptr = ptr1; // the reallocation succeeded, we can overwrite our original pointer now
}
Applying fixes as edits, based on the good comments below.
Reading this comp.lang.c question, reveals 3 cases:
"When it is able to, it simply gives you back the same pointer you handed it."
"But if it must go to some other part of memory to find enough contiguous space, it will return a different pointer (and the previous pointer value will become unusable)."
"If realloc cannot find enough space at all, it returns a null pointer, and leaves the previous region allocated."
This can be translated directly to code:
int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3, clean up then terminate.
free(ptr);
exit(0);
}
else if(tmp == ptr)
{
// Case 1: They point to the same place, so technically we can get away with
// doing nothing.
// Just to be safe, I'll assign NULL to tmp to avoid a dangling pointer.
tmp = NULL;
}
else
{
// Case 2: Now tmp is a different chunk of memory.
ptr = tmp;
tmp = NULL;
}
So, if you think about it, the code you posted is fine (almost). The above code simplifies to:
int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3.
free(ptr);
exit(0);
}
else if(ptr != tmp)
{
ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;
Note the extra else if(ptr != tmp), which excludes Case 1, where you wouldn't want to call free(ptr) because ptr and tmp refer to the same location. Also, just for safety, I make sure to assign NULL to tmp to avoid any dangling pointer issues while tmp is in scope.
OP: ... may be different from ptr, or NULL if the request fails.
A: Not always. NULL may be legitimately returned (not a failure), if count is 0.
OP: Is it sufficient to just assume that the reallocated pointer points to a different block of memory and not to the same block.
A: No
OP: Should I put in another condition which will compare the equality of ptr and ptr1 and exclude the execution of the free(ptr) statement?
A: No.
If realloc() returns NULL (and count is not 0), the value of ptr is still valid, pointing to the un-resized data. free(ptr) or not depends on your goals.
If realloc() returns not NULL, do not free(ptr), it is all ready freed.
Example: https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper
#include <assert.h>
#include <stdlib.h>
int ReallocAndTest(char **Buf, size_t NewSize) {
assert(Buf);
void *NewBuf = realloc(*Buf, NewSize);
if ((NewBuf == NULL) && (NewSize > 0)) {
return 1; // return failure
}
*Buf = NewBuf;
return 0;
}
realloc will return the same address to ptr if it have enough space to extend the actual chunk of memory pointed by ptr. Otherwise, it will move the data to the new chunk and free the old chunk. You can not rely on ptr1 being different to ptr. Your program behaves undefined.
If realloc returns another address, it first deallocates the old one so you don't have to do it yourself.
By the way, never cast the return of malloc/realloc :). Your code should be like this:
ptr=malloc(sizeof(int));
ptr=realloc(ptr,count*sizeof(int));
if(ptr==NULL)
{
// error!
printf("\nExiting!!");
// no need to free, the process is exiting :)
exit(0);
}
If realloc moves your data, it will free the old pointer for you behind the scenes. I don't have a copy of the C11 standard, but it is guaranteed in the C99 standard.
You should not free your original pointer if the realloc succeeds. Whether you free that pointer if the realloc fails depends on the needs of your particular application; if you absolutely cannot continue without that additional memory, then this would be a fatal error and you would deallocate any held storage and exit. If, OTOH, you can still continue (perhaps execute a different operation and hope that memory will come available later), the you'd probably want to hold on to that memory and a attempt a another realloc later.
Chapter and verse:
7.22.3.5 The realloc function
Synopsis
1 #include <stdlib.h>
void *realloc(void *ptr, size_t size);
Description
2 The realloc function deallocates the old object pointed to by ptr and returns a
pointer to a new object that has the size specified by size. The contents of the new
object shall be the same as that of the old object prior to deallocation, up to the lesser of
the new and old sizes. Any bytes in the new object beyond the size of the old object have
indeterminate values.
3 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.
Returns
4 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.
Emphasis added. Note clause 4; the returned pointer may be the same as your original pointer.

Resources