Realloc allocation in C - c

Hello I try to understand how realloc works so here is my question:
Let's say that first we call malloc in order to allocate enough memory for 1 int.
int *p=malloc(sizeof(int))
then we call realloc like this:
p=realloc(p,sizeof(int)*2);
The pointer p points to memory with available space for 2 or 1+2 ints?

As mentioned in the man pages:
void *realloc(void *ptr, size_t size);
[...]
The realloc() function changes the size of the memory block pointed
to by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes. If the new size is larger than the old size, the added memory
will not be initialized. [...]
(My emphasis). In other words, the size parameter to realloc asks for how many bytes of memory you'd like allocated in total, not the number of bytes of memory that you'd like to add.
Hope this helps!

void* realloc (void* ptr, size_t size);
Changes the size of the memory block pointed to by ptr.
The function may move the memory block to a new location (whose address is returned by the function).
The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location. If the new size is larger, the value of the newly allocated portion is indeterminate.
In case that ptr is a null pointer, the function behaves like malloc, assigning a new block of size bytes and returning a pointer to its beginning.
In C90 (C++98):
Otherwise, if size is zero, the memory previously allocated at ptr is deallocated as if a call to free was made, and a null pointer is returned.
In C99/C11 (C++11):
If size is zero, the return value depends on the particular library implementation: it may either be a null pointer or some other location that shall not be dereferenced.
Argument ptr:
Pointer to a memory block previously allocated with malloc, calloc or realloc.
Alternatively, this can be a null pointer, in which case a new block is allocated (as if malloc was called).
Argument size:
New size for the memory block, in bytes.
size_t is an unsigned integral type.
Return Value:
A pointer to the reallocated memory block, which may be either the same as ptr or a new location.
The type of this pointer is void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
In C90 (C++98):
A null-pointer indicates either that size was zero (an thus ptr was deallocated), or that the function did not allocate storage (and thus the block pointed by ptr was not modified).
In C99/C11 (C++11):
A null-pointer indicates that the function failed to allocate storage, and thus the block pointed by ptr was not modified.

From realloc(3)
Synopsis
void *realloc(void *ptr, size_t size);
Description
The realloc() function changes the size of the memory block pointed to by ptr to size bytes.

Related

Can I realloc() an unallocated pointer?

Normally, realloc() is used to reallocate a previously allocated pointer:
int *DynamicArray = malloc(sizeof(int)*SomeArbitraryValue);
// Some rando code where DynamicArray is used
DynamicArray = realloc(DynamicArray, sizeof(int)*SomeOtherArbitraryValue)
But can realloc() be used to directly allocate memory? As in
int *DynamicArray = realloc(/*...*/);
Can realloc() handle non-preallocated pointers?
Yes, just pass NULL to it's first argument.
The manpage of realloc(3) says ...
The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will not be initialized. If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an
earlier call to malloc(), calloc(), or realloc(). If the area pointed to was moved, a free(ptr) is done.
As the answer by #ZhangBoyang tells you, yes, assuming one possible interpretation of your question. However the way you've worded your question ("non-preallocated pointers") suggests you may have misunderstanding of some of the concepts involved. malloc does not "allocate pointers". It allocates objects, and pointers are values that point to objects. The lifetime of those objects are not connected to the lifetime of any particular pointer pointing to them.
Passing a pointer to realloc doesn't "do anything to" the pointer. It does something to the object pointed to by it. If the pointer is uninitialized or invalid, the call has undefined behavior and bad things will happen. If the pointer is a null pointer, however, realloc(ptr, n) will behave exactly as malloc(n).

Does sizeof returns the amount of memory allocated?

I read that:
sizeof operator returns the size of the data type, not the amount of memory allocated to the variable.
Isn't the amount of memory allocated depends on the size of the data type? I mean that sizeof will return 4 (architecture-dependent) when I pass int to it.
Am I missing something here?
sizeof returns the number of bytes that a variable or stack allocated array occupies.
Examples:
sizeof(char)=1 (in most configurations)
But sizeof(char*)=8 (depending on the platform)
If you dynamically allocate memory with malloc, you will receive a pointer to that block of memory. If use the sizeof on it, you will just get the size of the pointer.
However, sizeof() a stack allocated array like when you write int a[10] is the size of the allocated memory (so 4*10)
The size of the pointer doesn't depend on the size of the datatype it represents. (On 32 bit platforms, a pointer is 32bit)
The text you quote is technically incorrect. sizeof variable_name does return the size of memory that the variable called variable_name occupies.
The text makes a common mistake of conflating a pointer with the memory it points to. Those are two separate things. If a pointer points to an allocated block, then that block is not allocated to the pointer. (Nor are the contents of the block stored in the pointer -- another common mistake).
The allocation exists in its own right, the pointer variable exists elsewhere, and the pointer variable points to the allocation. The pointer variable could be changed to point elsewhere without disturbing the allocation.
sizeof returns the number of bytes
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type.
but the size of each byte is not guaranteed to be 8. So you don't obtain directly the amount of memory allocated.
A byte is composed of a contiguous sequence of bits, the number of which is implementation-defined
anyway you can deduce the amount of memory allocated using the CHAR_BIT constant, which contains the number of bit is a byte.
"Memory allocation" in C typically refers to explicit allocation (i.e: on the heap - malloc() and friends), or implicit allocation (i.e: on the stack).
As you've defined, sizeof() returns the size of the data type:
sizeof(char) - a single char
sizeof(void *) - an void pointer
If you call malloc(sizeof(int)), you're requesting "enough memory to hold the data for an int", which may be 4 bytes on your system... you may find that more memory than you requested is allocated (though this will typically be hidden from you, see canaries).
Additionally, if you call int *x = malloc(1024), and sizeof(*x), you might get 4, because an int happens to be 4 bytes... even though the memory you've allocated is 1 KiB. If you were to incorrectly call sizeof(x), then you'll get the size of a pointer returned, not the size of the type it points to. Neither of these (sizeof(*x) or sizeof(x)) will return 1024.

How does realloc() reallocate the memory?

How does realloc() reallocate the memory which was first allocated by malloc()?
I know that you need to use malloc() before you´re able to reallocate the memory, but I don´t understand how that really should work. What if a dynamic-memory object gets decreased in size by realloc()? Is this respective piece of the object just erased after the call to realloc()?
My Question is:
How does the realloc() function reallocate a dynamic-memory object created by malloc()?
Note: I did this Q&A because many beginners seem to be still confused about the issue of reallocating memory using realloc() despite already existing questions here on SO for that topic. They seem to be a little confusing for anyone who is new to the topic and still do not represent the whole behavior of realloc(). Therefore, and because the questions, IMHO, still do not quite fit the answer I´d want to give, I made my own Q&A.
Note: All citations in the following answer are quoted from the actual C standard, ISO/IEC 9899:2018 (C18), section 7.22.3.4.
First, the synopsis for the realloc() function from ISO/IEC 9899:2018, Section 7.22.3:
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
Despite its name, the realloc() function does not "reallocate" anything. realloc() is not modifying an extant object in memory. Instead, it does some sort of "create (new object) & copy the data" routine.
If size is not 0 and ptr either points to an object that was allocated by one of the memory management functions (not just malloc() only) or points to NULL, then realloc() usually creates a new object and copies the data from the old object into the new object.
*I do say usually because you can´t assume that a new object in memory is really allocated. You must always check whether or not it was allocated by checking whether the returned pointer points to NULL.
If the size of the new object is larger than the old object, the bytes of the new object that are beyond the size of the old object have indeterminate values. If the new object is shorter than the old object, the values inside the difference between are thrown away. Every other value remains in the new object as it was in the old one.
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.
After that, if:
ptr is not a pointer to NULL and is a pointer earlier returned by a memory management function, and the object this pointer is pointing to has not been deallocated before the call to realloc(),
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.
size is not 0,
If size is zero and memory for the new object is not allocated, it is implementation-defined whether the old object is deallocated. If the old object is not deallocated, its value shall be unchanged.
and a new object could really be allocated if realloc() did not return a pointer to NULL,
If size is nonzero and memory for the new object is not allocated, the old object is not deallocated
and really only if all of these premises are fulfilled, realloc() deallocates the memory of the old object and returns a pointer with the address of the new object in memory.
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.
If realloc() returns a pointer to NULL, no new object is created and the old object remains unchanged at its address in memory.
Optionally, to make the "pseudo-reallocating" behavior almost perfect, it is possible that the new object, after the deallocation of the old object is done (if it happens), is allocated back at the same address in memory where the old object was stored.
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 has not been allocated.
In this case, there are logically two data copying processes in realloc(), one time into a buffer object and later back to the place of where the original old object was stored. The buffer object is deallocated after the execution of realloc()is completed.
The pointer of ptr which first is used for pointing to the old object should not be used for the returned pointer. If the call statement to realloc() looks like this:
ptr = realloc(ptr,size);
then you usually have a memory leak if the reallocation fails because you just overwrote the pointer to the old memory with a null pointer. If you don't have another pointer that points to it, you've leaked the memory.
Therefore, it is usually better to use a variant on:
void *new_space = realloc(ptr, new_size);
if (new_space == NULL)
{
/* …handle out of memory condition… */
/* ptr is still valid and points to the previously allocated data */
return; /* Or otherwise do not continue to the following code */
}
ptr = new_space;
size = new_size;
Note that according to what I´ve said above, the address may be the same as before the call to realloc().
To make sure that memory management is really happening that way, we can try this experiment:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t length1 = 4;
size_t length2 = 2;
int *ptr1 = malloc(sizeof(*ptr1) * length1);
if(ptr1 == NULL)
{
printf("The object could not be allocated!\n");
return 1;
}
printf("value (not address) of ptr1 before realloc(): %p\n", (void *)ptr1);
ptr1 = realloc(ptr1,length2);
if(ptr1 == NULL)
{
printf("No new object allocated. Old object remains!\n");
return 1;
}
printf("value (not address) of ptr1 after realloc(): %p\n", (void *)ptr1);
free(ptr1);
return 0;
}
At my try it gave the output of:
value (not address) of ptr1 before realloc(): 0x1db4010
value (not address) of ptr1 after realloc(): 0x1db4010
So, the address stored in ptr1 after the use of realloc() is equivalent to before the call of it.
Additional Notes:
realloc() acts as malloc() when ptr is a NULL pointer:
int *ptr = NULL;
size_t length = 4;
ptr = realloc(ptr,sizeof(*ptr) * length);
shall have the same effect as,
int *ptr;
size_t length = 4;
ptr = malloc(sizeof(*ptr) * length);
If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size.
But, in my personal opinion, you should not first allocate dynamic storage by the use of realloc(). I recommend that you always use malloc() or another allocating memory management function instead. It may cause some difficulties to future readers.
You should not use realloc(ptr,0) as substitution for free(ptr) to deallocate the dynamic memory because it is implementation-defined whether the old object is really deallocated or not.
If size is zero and memory for the new object is not allocated, it is implementation-defined whether the old object is deallocated. If the old object is not deallocated, its value shall be unchanged.
Always use free() to deallocate a dynamically allocated object.

How free memory after of realloc

Is correct ways to free up memory in this code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void ){
char *string1, *string2;
string1 = (char*) malloc(16);
strcpy(string1, "0123456789AB");
string2 = realloc(string1, 8);
printf("string1 Valor: %p [%s]\n", string1, string1);
printf("string2 Valor: %p [%s]\n", string2, string2);
free(string1);
free(string2);
return 0;
}
Since the two pointers point to the same direction
I think your confusion comes from the (uninspired) expression "free pointers" (you used in your post, but edited it out since). You don't free pointers. You free memory. The pointer is just telling which memory.
In your example you have: the memory obtained from malloc. string1 points to this memory. Then when you call realloc a new memory block is obtained (possibly starting at the same address, possibly not), but realloc takes care to release the old one if needed (and is therefore undefined behavior to access or free it yourself). string2 points to this new memory block.
So you have to free just the memory block obtained from realloc. string2 points to that memory.
In short, no.
Per the C Standard:
7.22.3.5 The realloc function
...
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.
Once you call realloc(), you do not have to free() the memory addressed by pointer passed to realloc() - you have to free() the memory addressed by the pointer realloc() returns. (Unless realloc() returns NULL, in which case the original block of memory - passed to realloc() - has to be free()'d.)
When you call realloc, either the returned pointer is the same as the original, or a new pointer is returned and the original pointer becomes invalid. In the first case, calling free on both string1 and string2 results in a double-free since the pointers are equal. In the second case, calling free on string1 is a double-free since it was already freed.
So either way you have a double-free which results in undefined behavior.
From the man page for realloc:
void *realloc(void *ptr, size_t size);
The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes. If the new size is larger than the old size, the added memory
will not be initialized. If ptr is NULL, then the call is equivalent
to malloc(size), for all values of size; if size is equal to zero, and
ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr
is NULL, it must have been returned by an earlier call to malloc(),
calloc() or realloc(). If the area pointed to was moved, a free(ptr)
is done.
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.
Also from the man page for free:
The free() function frees the memory space pointed to by ptr, which
must have been returned by a previous call to malloc(), calloc() or
realloc(). Otherwise, or if free(ptr) has already been called before,
undefined behavior occurs. If ptr is NULL, no operation is performed.
You only need to free(string2).
Short answer: in your code, calling free(string2) is correct, and sufficient. Calling free(string1) is incorrect.
When you called realloc (and assuming that the call succeeded), its return value (which you stored in string2) became the one and only way to refer to the one block of memory that you have.
It may be that realloc resized your memory block "in place", meaning that the values of string2 and string1 are equal. In that case, calling free(string1) is wrong because you're freeing the same pointer twice.
It may be that realloc moved your data to a new place in the process of resizing it. In that case, the values of string2 and string1 are unequal. But in that case, after it finds a new place for your data and copies it there, realloc automatically frees the old block for you. So, again, calling free(string1) is wrong because you're freeing an already-freed pointer.
Think of realloc as something equivalent to:
void *
realloc(void *old, size_t new_size)
{
size_t old_size = magic_internal_function_that_knows_the_size_of(old);
void *new = malloc(new_size);
if (new == NULL)
return NULL;
memcpy(new, old, new_size > old_size ? old_size : new_size);
free(old);
return new;
}
If you have the magic function that can figure out how big an allocation is from the pointer, you can implement realloc yourself like this. malloc pretty much must have this function internally for free to work.
realloc can also do clever things like figuring out that you're reallocating to a smaller size and just free part of your allocation or figure out that you're growing your allocation and there's enough space after to fit it. But you don't need to think about those cases. Thinking that realloc is malloc+memcpy+free will not mislead you except that you need to remember that realloc failing and returning NULL means it didn't do the free.
The realloc implicity frees the input, it may not do anything at all, but you cannot free it after to re-alloced memory. So
char *string1, *string2;
string1 = (char*) malloc(16);
....
string2 = realloc(string1, 8); // this line implicitly frees string1
free(string1); // this is wrong !!!
free(string2);

Successive pointer allocations; Reallocated or allocated distinct?

If I allocate memory to pointers in a loop successively, does the compiler consider it as a single instance? Concretely:
for (i = 0; i < SOME_VAL; i++)
{
char *p = NULL;
p = malloc(sizeof(char));
SEND_POINTER_ON_NETWORK(p);
}
Will the compiler at every execution create a new instance of p or will it continue allocating memory to p? I am using VS2010.
char *p = NULL;
p = malloc(sizeof(char));
Each call to malloc() within the loop allocates new memory location to the pointer p , if you are trying to extend the already allocated memory to p then use realloc().
The memory management system looks for a free memory slot at the size of the argument in malloc (in this case sizeof(char)). You do not free the memory from one iteration to the next. Therefore, the memory management system 'sees' the memory as occupied and allocates a new memory slot to pointer p.
You have a memory leak in your code.
From ISO/IEC 9899:
(known as c99 standard)
7.20.3.3 The malloc function
Synopsis
1 #include <stdlib.h>
void *malloc(size_t size);
Description
2 The malloc function allocates space for an object whose size is specified by size and
whose value is indeterminate.
Returns
3 The malloc function returns either a null pointer or a pointer to the allocated space.
The behaving you expect would be made by realloc, which is described as follows:
7.20.3.4 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 the
calloc, malloc, or realloc 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.
Also notable is the fact, that MSVC compiler isn't strict conform to the standard in all topics.
But in the both cited cases I know they are conform with it. So it is also valid for your question.

Resources