How many bytes will be deallocated with free() after changing the pointer? - c++

I have following piece of code.
char* p = malloc(10);
p = p + 1;
free(p);
In above code,
How does malloc return the memory address when call malloc(10)?
How many bytes will be deallocated with free(p)?
How does free() know how many bytes to be deallocated?

As the man page for free will tell you, any argument except a pointer returned from malloc has undefined behaviour:
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
Regarding how free knows the size of the block: a typical memory allocator implementation has a header for each block (containing size, freelist pointers, etc.) and free knows the size of this header and the offset from the pointer returned by malloc.
This also answers your first question: malloc allocates such a block and returns a pointer to the start of the actual object.

Related

c++ realloc same pointer warranty

Using the std::realloc function:
If the new size is smaller, does it always have warranty to keep the memory block on the same position and only make it smaller, or it can move sometimes the whole block?
The reason to ask this, is that we'are writing a large and very hard code, and it is useful to make read only all the variables we need to leave unchanged, to obtain compiler's errors, when we try to change the wrong variable.
#include<cstdlib>
#include<iostream>
using namespace std;
int main(){
//From 10,000,000 unsigned ints to 10 unsigned ints
unsigned int * const array=new unsigned int[10000000];
cout<<array<<endl;
realloc(array,10*sizeof(unsigned int));
cout<<array<<endl;
delete array;
return 0;
}
Although I agree with the other answers in that you should not depend on it, there is an answer to be found in the glibc source. (I am assuming that you are using glibc, as you have not (yet) answered my comment asking which C library you are using)
EDIT: Using realloc on memory allocated by new is indeed disallowed, as other answers have mentioned.
Memory allocated without internally using mmap
If a block of memory is not allocated with mmap, __libc_realloc calls the _int_realloc function, which contains the following snippet of code:
if ((unsigned long) (oldsize) >= (unsigned long) (nb))
{
/* already big enough; split below */
newp = oldp;
newsize = oldsize;
}
This makes the pointer to the new memory equal the pointer to the old memory and sets the size accordingly. Note the split below comment; the old memory block may be resized to the requested size, but is not moved.
Memory allocated internally using mmap
If the memory was internally allocated using mmap, there are two ways of resizing the memory area; mremap_chunk or a series of calls to malloc, memcpy and free. If the mremap_chunk function is available, it is used instead of the latter option.
Memory reallocated using mremap_chunk
The function mremap_chunk contains this snippet of code
/* No need to remap if the number of pages does not change. */
if (size + offset == new_size)
return p;
If the number of pages does not change from the old size to the new size, there is no need to remap and the old pointer is returned.
Memory reallocated using malloc, memcpy and free
If mremap_chunk is not available, the __libc_realloc source continues with the following:
/* Note the extra SIZE_SZ overhead. */
if (oldsize - SIZE_SZ >= nb)
return oldmem; /* do nothing */
If the oldsize variable minus the chunk size is more than or equal to the new size, just return the old memory.
Well then, here we are. In all cases, glibc returns a pointer to the old memory, not moving it (but possibly resizing it). If you are using glibc (and can somehow guarantee that the only C library you are using it with is glibc, and can guarantee that it won't change at some point in the future), you are able to rely on the behavior that realloc does not move a block of memory if the requested size is equal to or less than the old size.
No!! If realloc succeeds, the old pointer (unless it was a nullpointer) is indeterminate.
Also, do not mix incompatible memory-management-functions (assume incompatibility unless guaranteed otherwise).
realloc only has the guarantees explicitly given in the standard:
If return-value is non-0: New pointer points to of at least size byte, the first min(oldsize, newsize) being equal to the passed block.
Else if size is non-0, nothing happened to the passed block.
Else the old block may have been deallocated, or not.
Moral: Never pass a 0 size to realloc, and only use the old pointer for anything (including comparison to the new pointer), if realloc failed (or you passed a nullpointer).
7.22.3.5 The realloc function
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
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.
C99 draft 7.20.3.4 says:
[#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.
You should not assume it.
And also: don't mix new and realloc as πάντα already wrote in the comments.
Nothing's guaranteed about realloc. It might shrink the block in place, or it might allocate a new one and copy the data. It might also fail.
An important point: realloc is only for reallocating memory that was previously allocated by malloc. In your code above, you are using new which has no equivalent for reallocation.
Also realloc actually returns the address of the new memory block, so in your code above you will be a) leaking this and b) referencing/freeing potentially already de-allocated memory.

Deallocating memory using a pointer to an element in an array

I have the following C++ code:
int main(){
unsigned char *abc = (unsigned char *)calloc(100,1);
unsigned char *def = &abc[50];
delete def;
}
Would this deallocate all the memory allocated by the call to calloc, or just the memory starting at the memory location where def points to?
It is undefined behavior. A crash, if you are lucky.
According to C++ standard (Working Draft, N3291=11-0061)
3.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]
...
The value of the
first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation
function is one supplied in the standard library, the call has no effect. Otherwise, the behavior is undefined
if the value supplied to operator delete(void*) in the standard library is not one of the values returned
by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, constvstd::nothrow_t&) in the standard library ...
There are several problems here. First, you should use free if you used calloc.
Then, you should pass to free the same pointer you got from calloc.
calloc allocates memory as one continuous block, and the entire block gets deallocated with free, not a part of it.
See http://www.cplusplus.com/reference/cstdlib/calloc/.
delete can only delete memory allocated with new.
for memory allocated with calloc deallocate it using free.
and no, you can't just use a pointer to somewhere inside the allocated memory.
in C++, deal with simple character strings by using std::string from the <string> header.
it takes care of memory management for you.
It wouldn't necessarily deallocate anything as it has undefined behavior. You can only call delete on a pointer which was allocated with new. Not only was the memory allocated with calloc instead of new, but you are also not passing a pointer to what calloc returned, but to some other position within that block of memory.
Isn't *abc undefined there? delete def; wouldn't do anything if there is nothing to delete!

"Delete" not de-allocating dynamic memory [duplicate]

This question already has answers here:
C++ delete - It deletes my objects but I can still access the data?
(13 answers)
Closed 9 years ago.
I'm facing an issue. I wrote the following programme:
void main()
{
int *ptr;
ptr=new int;
cout<<ptr<<endl;
cout<<&ptr<<endl;
delete ptr;
// ptr= NULL;
cout<<ptr<<endl;
cout<<&ptr<<endl;
}
The output of the programme is:
0x00431810
0x0018FF44
0x00431810
0x0018FF44
"&ptr" would definitely be the same because it is ptr's own address. But 1st and third line of output clearly shows that "ptr" is pointing to the same memory location even after the "delete" is called. Why? If this is the case why do we have "delete" and not just rely on NULLING the pointer. I know that more than one pointers can point to a memory location but yeah "delete" is useless. No ? That's so confusing. please help. I've an exam tomorrow.
delete ptr does not change the value of the pointer, but it does free the memory.
Note that dereferencing ptr after freeing the memory would trigger undefined behaviour.
When you call new, you are asking the computer to allocate some memory on the heap and returns a pointer to where that is on the heap.
Calling delete does the opposite in that it tells the computer to free the memory the pointer is pointing to from the heap. This means that it can be reused by your program at a later stage.
However, it does not change the value of the pointer. It is good practise to set the pointers value to NULL. This is because, where the pointer is now pointing to could contain anything (the computer is free to reuse this memory for something else). Were you to use this pointer, it is undefined what will happen.
If you just change the pointer to NULL, then all that does it forget where you allocated the memory. Because C++ is not a managed language, it won't detect you don't have any pointer to that memory, so the memory will become lost as you can't access it (you don't know where it is) but the computer can't reuse it (it doesn't know you are done with it).
If you use a managed language like C# or Java, when there are no pointers to something on the heap, the computer frees it (known as Garbage Collection) but this comes with performance overheads so C++ leaves it up to the programmer.
pointer doesn't know if the memory is valid or corrupted. You can make pointer to point at any address that you can address (that will fit into pointer). For example on my machine pointer has 8 bytes size so I can do
int main(int argc, char** argv) {
int *ptr;
ptr=new int;
cout<<ptr<<endl;
cout<<&ptr<<endl;
delete ptr;
//ptr= NULL;
cout<<ptr<<endl;
cout<<&ptr<<endl;
ptr = (int*) 0xffffffff;
cout<<ptr<<endl; //prints 0xffffffff
ptr = (int*) 0xffffffffffffffff;
cout<<ptr<<endl; //prints 0xffffffffffffffff
ptr = (int*) 0xffffffffffffffff1;
cout<<ptr<<endl; //prints 0xfffffffffffffff1 truncated
ptr = (int*) 0xffffffffffffffff321;
cout<<ptr<<endl; //prints 0xfffffffffffff321 truncated
return 0;
}
When you are using new it will allocate memory at some address on the heap and return you a pointer to this address.
void* operator new (std::size_t size) throw (std::bad_alloc);
Pointer and memory are two distinguished things. In particular you can even specify an address which you want to use for allocation by hand(using placement new syntax):
int* ptr = new (0xff1256) int;
//correct if the memory at 0xff1256 is preallocated
//because placement new only creates object at address
//doesn't allocate memory
"ptr" is pointing to the same memory location even after the "delete"
is called. Why?
In the same way delete ptr only deallocates memory, leaving the pointer intact (this is a good practice though to assign NULL to a pointer immediately after call to delete). It only deallocate the memory, it is not interested in your pointer but in the address where to free memory. Allocating memory or deallocating it is done by operating system (i.e.the memory is being marked as allocated).
From the documentation,
Deallocates the memory block pointed by ptr (if not null), releasing
the storage space previously allocated to it by a call to operator new
and rendering that pointer location invalid.
That means, delete marks the location to be reused by any other process for any other purpose. It never says that, it will initialize the memory block to any random value, so that the earlier stored data can never be accessed again. So, there is always the possibility of having your data even after the call to delete. But, again, it is just one of the possibility of Undefined Behavior. Thats' why coders, make the pointer NULL after deallocating it.

Does c++ realloc function applies delete operation for old data block if moving data to different block?

The function may move the memory block to a new location, in which case the new location is returned.
For example I have a pointer to an array:
int *arr; // somewhere next it initialized, filled with elements and etc
Somewhere I need to:
void* location = realloc(arr, NEW_SIZE);
What will happen with old memory block place?
If realloc return pointer that not math to arr, should i use next code?:
delete arr;
arr = (int*)location;
The function realloc is inherited from good old C. It does not run destructors or do any other C++ magic. It can also only be applied to blocks allocated using malloc (and friends) -- it can not be used for blocks allocated using 'new'.
Rule #1: dont mix new/delete with malloc/free.
If you're allocating with malloc() in the first place and you need a bigger heap space then you need to call realloc() which will return you a new pointer which may not map to the same memory areas as arr therefore you should not use it.
Free malloc'ed/realloc'ed space with free
realloc(void *ptr, size_t new_size) requires the given area of memory that ptr points to to be previously allocated by malloc(), calloc() or realloc() and not yet freed with free(), otherwise, the results are undefined.
Use realloc only with malloc, calloc or another realloc and clean it up with free.
In C++ use always new with delete and new[] with delete[].

using realloc in c

i am using void *realloc(void *pointer, size_t size); to increase the size of my pointer. how does realloc work?
does it create a nre address space, and copy the old value to the new address space and returns a pointer this address? or it just allocates more memory and binds it to the old one?
#Iraklis has the right answer: it does the second (if it can get away with it) or the first (but only if it has to).
However, sometimes it can do neither, and will fail. Be careful: If it can't resize your data, it will return NULL, but the memory will NOT be freed. Code like this is wrong:
ptr = realloc(ptr, size);
If realloc returns NULL, the old ptr will never get freed because you've overwritten it with NULL. To do this properly you must do:
void *tmp = realloc(ptr, size);
if(tmp) ptr = tmp;
else /* handle error, often with: */ free(ptr);
On BSD systems, the above is turned into a library function called reallocf, which can be implemented as follows:
void *reallocf(void *p, size_t s)
{
void *tmp = realloc(p, s);
if(tmp) return tmp;
free(p);
return NULL;
}
Allowing you to safely use:
ptr = reallocf(ptr, size);
Note that if realloc has to allocate new space and copy the old data, it will free the old data. Only if it can't resize does it leave your data intact, in the event that a resize failure is a recoverable error.
It depends! If its unable to resize the memory region in place then it allocates a new memeory region, copy the old data and free the old memory.
You're misusing the term "address space". All of the memory of your process exists within a single address space. The memory not used by your program, its global variables, and its stack are known as the "heap". malloc and realloc (and calloc, which is just malloc and clear) allocate memory from the heap. Most implementations of realloc will check if there is enough (size bytes) free space starting at pointer (which must point to a block previously allocated by malloc or realloc -- realloc knows how large that block is) and, if so, just increase the size of the block allocated at the location given by pointer and return, with no copying. If there isn't enough space, it will do the equivalent of newptr = malloc(size); memcpy(newptr, pointer, size_of_old_block); free(pointer); return newptr; ... that is, it will allocate a block big enough to hold size bytes, copy the data at pointer to that block, free the old block, and return the address of the new block.
I think the answer is function is dependent on the requested size and available heap.
From the programmers perspective, I think all we get guaranteed is that pointer is non-null if the new allocation is successful. The pointer may, therefore, remain unchanged even though it now points to a larger block of memory represented by size_t.
Realloc does not change the size of your pointer, the size of pointers is always the same on the same architecture. It changes the size of the allocated memory to which your pointer points. The way it works is described here: http://msdn.microsoft.com/en-us/library/xbebcx7d.aspx. In short, yes, it allocates more memory leaving your content unchanged; if the memory must be moved, it copies the content. OF course, you can specify a shorter size, in which case it trims the allocated memory, again leaving the content untouched.