pkthapa
pkthapa

Reputation: 1071

Does free() operator delete the address from the dynamic variable?

Let's consider below program:

int main ()
{
    int *p, *r;
    p = (int*)malloc(sizeof(int));

    cout<<"Addr of p  = "<<p <<endl;
    cout<<"Value of p = "<<*p <<endl;

    free(p);
    cout<<"After free(p)"<<endl;

    r = (int*)malloc(sizeof(int));
    cout<<"Addr of r  = "<<r <<endl;
    cout<<"Value of r = "<<*r <<endl;

    *p = 100;
    cout<<"Value of p = "<<*p <<endl;
    cout<<"Value of r = "<<*r <<endl;
    return 0;
}

Output:

Addr of p  = 0x2f7630
Value of p = 3111728
free(p)
Addr of r  = 0x2f7630
Value of r = 3111728
*p = 100
Value of p = 100
Value of r = 100

In the above code, p and r are dynamically created. p is created and freed. r is created after p is freed. On changing the value in p, r's value also gets changed. But I have already freed p's memory, then why on changing p's value, r's value also gets modified with the same value as that of p?

I have come to below conclusion. Please comment if I am right?

Explanation: Pointer variables p and q are dynamically declared. Garbage values are stored initially. Pointer variable p is freed/deleted. Another pointer variable r is declared. The addresses allocated for r is same as that of p (p still points to the old address). Now if the value of p is modified, r’s value also gets modified with the same value as that of p (since both variables are pointing to the same address). The operator free() only frees the memory address from the pointer variable and returns the address to the operating system for re-use, but the pointer variable (p in this case) still points to the same old address.

Upvotes: 3

Views: 608

Answers (4)

pkthapa
pkthapa

Reputation: 1071

free() frees the heap memory to be re-used by OS. But the contents present in the memory address are not erased/removed.

Upvotes: 0

Peter
Peter

Reputation: 36617

Your analysis is superficially close in some ways but not correct.

p and r are defined to be pointers in the first statement of main(). The are not dynamically created. They are defined as variables of automatic storage duration with main(), so they cease to exist when (actually if, in the case of your program) main() returns.

It is not p that is created and freed. malloc() dynamically allocates memory and, if it succeeds, returns a pointer which identifies that dynamically allocated memory (or a NULL pointer if the dynamic allocation fails) but does not initialise it. The value returned by malloc() is (after conversion into a pointer to int, which is required in C++) assigned to p.

Your code then prints the value of p.

(I have highlighted the next para in italic, since I'll refer back to it below).

The next statement prints the value of *p. Doing that means accessing the value at the address pointed to by p. However, that memory is uninitialised, so the result of accessing *p is undefined behaviour. With your implementation (compiler and library), at this time, that happens to result in a "garbage value", which is then printed. However, that behaviour is not guaranteed - it could actually do anything. Different implementations could give different results, such as abnormal termination (crash of your program), reformatting a hard drive, or [markedly less likely in practice] playing the song "Crash" by the Primitives through your computer's loud speakers.

After calling free(p) your code goes through a similar sequence with the pointer r.

The assignment *p = 100 has undefined behaviour, since p holds the value returned by the first malloc() call, but that has been passed to free(). So, as far as your program is concerned, that memory is no longer guaranteed to exist.

The first cout statement after that accesses *p. Since p no longer exists (having being passed to free()) that gives undefined behaviour.

The second cout statement after that accesses *r. That operation has undefined behaviour, for exactly the same reason I described in the italic paragraph above (for p, as it was then).

Note, however, that there have been five occurrences of undefined behaviour in your code. When even a single instance of undefined behaviour occurs, all bets are off for being able to predict behaviour of your program. With your implementation, the results happen to be printing p and r with the same value (since malloc() returns the same value 0x2f7630 in both cases), printing a garbage value in both cases, and then (after the statement *p = 100) printing the value of 100 when printing *p and *r.

However, none of those results are guaranteed. The reason for no guarantee is that the meaning of "undefined behaviour" in the C++ standard is that the standard describes no limits on what is permitted, so an implementation is free to do anything. Your analysis might be correct, for your particular implementation, at the particular time you compiled, linked, and ran your code. It might even be correct next week, but be incorrect a month from now after updating your standard library (e.g. applying bug fixes). It is probably incorrect for other implementations.

Lastly, a couple of minor points.

Firstly, your code is incomplete, and would not even compile in the form you have described it. In discussion above, I have assumed your code is actually preceded by

#include <iostream>
#include <cstdlib>

using namespace std;

Second, malloc() and free() are functions in the standard library. They are not operators.

Upvotes: 3

Thomas Matthews
Thomas Matthews

Reputation: 57729

The free() function and the delete operator do not change the content of a pointer, as the pointer is passed by value.

However, the stuff in the location pointed to by the pointer may not be available after using free() or delete.

So if we have memory location 0x1000:

       +-----------------+  
0x1000 |                 |  
       | stuff in memory |  
       |                 |  
       +-----------------+  

Lets assume that the pointer variable p contains 0x1000, or points to the memory location 0x1000.

After the call to free(p), the operating system is allowed to reuse the memory at 0x1000. It may not use it immediately or it could allocate the memory to another process, task or program.

However, the variable p was not altered, so it still points to the memory area. In this case, the variable p still has a value, but you should not dereference (use the memory) because you don't own the memory any more.

Upvotes: 3

zwol
zwol

Reputation: 140788

Your analysis of what actually happened is correct; however, the program is not guaranteed to behave this way reliably. Every use of p after free(p) "provokes undefined behavior". (This also happens when you access *p and *r without having written anything there first.) Undefined behavior is worse than just producing an unpredictable result, and worse than just potentially causing the program to crash, because the compiler is explicitly allowed to assume that code that provokes undefined behavior will never execute. For instance, it would be valid for the compiler to treat your program as identical to

int main() {}

because there is no control flow path in your program that does not provoke undefined behavior, so it must be the case that the program will never run at all!

Upvotes: 2

Related Questions