int main()
{
int x = 0;
free(x);
}
This compiles and appears to be a no-op. What actually happens? is this behavior defined?
Thanks!
int main()
{
int x = 0;
free(x);
}
This compiles and appears to be a no-op. What actually happens? is this behavior defined?
Thanks!
No, the behavior is not defined. Moreover, the code is not supposed to compile.
Firstly, the code is not supposed to compile because it contains a constraint violation. The expression you are passing as an operand to free
has int
type. The parameter of free
has void *
type. The only case when an int
value can be implicitly converted to void *
type is when the int
value is an Integral Constant Expression (ICE) with value 0
. In your case x
is not an ICE, meaning that it is not implicitly convertible to void *
. The only reason your code compiles is that for historical reasons (to support legacy code) your compiler quietly overlooks the constraint violation present in the free(x)
call. I'm sure that if you elevate the level of warnings in your compiler, it will complain (at least with a warning). A pedantic compiler will immediately issue an error for free(x)
call. Try Comeau Online, for example in C89/90 mode:
"ComeauTest.c", line 6: error: argument of type "int" is incompatible with parameter
of type "void *"
free(x);
^
(Also, did you remember to include stdlib.h
before calling free
?)
Secondly, let's assume that the code compiles, i.e. it is interpreted by the compiler as free((void *) x)
. In this case a non-constant integral value x
is converted to pointer type void *
. The result of this conversion is implementation defined. Note, that the language guarantees that when an ICE with value of 0
is converted to pointer type, the result is a null pointer. But in your case x
is not an ICE, so the result of the conversion is implementation-defined. In C there's no guarantee that you will obtain a null pointer by converting a non-ICE integer with value 0
to pointer type. On your implementation it probably just happened that (void *) x
with non-ICE x
equal to 0
produces a null pointer value of type void *
. This null pointer value, when passed to free
, results in a no-op, per the specification of free
.
In general case though, passing such a pointer to free
will result in undefined behavior. The pointers that you can legally pass to free
are pointers obtained by previous calls to malloc
/calloc
/realloc
and null pointers. Your pointer violates this constraint in general case, so the behavior is undefined.
This is what happens in your case. But, again, your code contains a constraint violation. And even if you override the violation, the behavior is undefined.
P.S. Note, BTW, that many answers already posted here make the same serious mistake. They assume that (void *) x
with zero x
is supposed to produce a null pointer. This is absolutely incorrect. Again, the language makes absolutely no guarantees about the result of (void *) x
when x
is not an ICE. (void *) 0
is guaranteed to be null pointer, but (void *) x
with zero x
is not guaranteed to be null pointer.
This is covered in C FAQ http://c-faq.com/null/runtime0.html . For those interested in better understanding of why it is so it might be a good idea to read the entire section on null pointers http://c-faq.com/null/index.html
In your case, it works because calling free(NULL) (i.e., free(0)) is a NOOP. However, if you called it with any value other than 0 (NULL), the behavior would be undefined-- crashes and/or memory corruption are likely candidates.
EDIT: As others have pointed out later, free(x) (with x=0) and free(NULL) are not the same thing. (Though it is often 0, the value of the NULL pointer is implementation-defined, and cannot be relied upon.) Please see AndreyT's answer for a very good clarification.
Have you tried turning your compiler's warning level up? For example gcc -ansi -pedantic -W -Wall
reports:
tmp.c:6: warning: passing argument 1 of ‘free’ makes pointer from integer without a cast
The behaviour is undefined. Don't do it.
From the free
man page:
free() 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 behaviour occurs. If ptr is NULL, no operation is performed.
In your example, you're actually calling free(0)
, since free
accepts a pointer as an argument. You're essentially telling the runtime to free the memory at address 0, which has not been previously allocated by malloc
.
Since '0' is NULL, nothing will happen. (Thanks to the comments for pointing out my silly error).
It should throw an access violation on most architectures. OK it's a 0 so it works, but if it was not 0 it would fail. It's undefined. You can't free()
a stack allocated variable.
free() works on dynamically allocated memory, i.e., memory allocated with malloc, calloc, or realloc. Also, it takes a pointer, and you are passing teh value of x. There is no reason to call it on stack allocated variables that will be freed when the stack unwinds and that behavior is undefined. Always good to read the documentation.
free (0 ); "Calling free function with NULL value , will have no effect."
Actually it will make impact , when we are freeing the using memory.
Here x value is zero , So that it does not make any problem. If x has value other than
zero , in this case it may get segmentation fault . Because x value might be using as a
memory representation some other variables.