+25  A: 

Simple answer: because you might be freeing an expression, e.g. free(find_named_object("foo")).

In more detail: The free function takes a void* parameter, which is the address of the memory to free. This doesn't confer to the function any knowledge of the original variable that supplied the address (or, for that matter, whether there even exists a variable). Just setting the parameter passed in to NULL would do nothing either, since it's just a local copy of the address.

Marcelo Cantos
Passing an expression to free should not be a reason, because in C expressions are not first class objects. In your example, the expression returns a pointer, which in turn is passed to free.
Vijay Mathew
const char *s="foo"; char *p=(char*)s; free(p); - compiles ok
oraz
@Vijay, I don't understand your point. The expression does indeed return a pointer, which is then passed to free. How, then, can `p` be set to NULL? There is no `p` to set.
Marcelo Cantos
@oraz, that code doesn't compile. You are missing a `*`. I also don't see what relevance it has to my answer.
Marcelo Cantos
@Marcelo, sorry
oraz
There is absolutely no need to apologise @oraz. (In fact, perhaps I need to apologise; on rereading, my response is more abrupt than I intended.)
Marcelo Cantos
@Marcelo By "expression" you meant the pointer returned by find_named_object()? Then you are right. The statement "you might be freeing an expression" caused the confusion as you will always be freeing a pointer.
Vijay Mathew
@Vijay: I think by "expression" @Marcelo meant "rvalue". +1 Best answer, BTW.
Dan Moulding
Thanks for the clarifying remark @Dan. rvalue is exactly what I meant (and should have said :-).
Marcelo Cantos
@Marcelo: oraz's code, once you undo the markdown formatting applied, reads `const char *s="foo"; char *p=(char*)s; free(p);`. (That's why you thought it was missing asterisks.)
Roger Pate
Thank you, @Roger. I should have noticed the italics.
Marcelo Cantos
+22  A: 

If it did, you would have to pass a pointer to a pointer to the function:

int * p = malloc( sizeof( int ));
free( & p );

which I'm sure many people would get wrong.

anon
This, plus of course many times p is only going to be a local stack variable anyway in which case having set it to NULL becomes irrelevant as soon as it goes out of scope. Also, if there are multiple references to the same block of memory then they wouldn't all end up set to NULL if one of them was free'd, so it really wouldn't help much.
Vicky
And since there is no generic pointer-to-pointer type, you would need a separate `free` for each type of pointer.
caf
caf: what about void **?
knittl
@caf, actually there is: void **.
iconiK
In C++ free() could take a reference to a pointer and the syntax is the same, but for C compatibility it probably won't ever do that.
AshleysBrain
`void **` is **not** a generic pointer to pointer type. `void **` is a pointer to specific object type: `void *`. A `void **` pointer should only ever be dereferenced if it points to an actual `void *`.
caf
caf
@caf Make it a template.
anon
@Neil: Perhaps some people would get it wrong, but that's not really a valid reason for why it's not done that way. @Marcelo's answer cuts to the heart of the matter, which is that there is no guarantee that the argument passed to `free` will be an **lvalue**.
Dan Moulding
@Dan well obviously if we are changing the way free() works, we can specify that its parameter must be an lvalue.
anon
I've often wished free would return NULL so freeing a pointer and setting it to NULL could be achieved in a single stroke. Not that big a deal that it doesn't work that way, though.
James Morris
@Neil: we're not changing the way it works, we're explaining why it works the way it does ;)
Dan Moulding
+5  A: 

Because function parameters are passed by value in C. That is, if p == 0x12345 you pass '0x12345' to free(), not p "itself".

stereofrog
+2  A: 

In C, calling a function can never alter the value of the parameters you pass in, so if free(p) altered the value of p by setting it to NULL then this behaviour would be very non-standard indeed.

Paul Stephenson
+7  A: 

C function parameters are always passed by value, so in order to modify the pointer passed to free() you would need to pass a pointer to the pointer being deallocated, which can lead bugs caused by forgotten & operators.

Secondly, if that pointer had any aliases, the programmer would still be responsible for nulling them out. I could see problems caused by programmers assuming that all references were set to NULL.

Finally, it's not always necessary to set the pointer to NULL. Imagine a function which allocates some memory, does some work and frees it before returning. I could see how setting the pointer to NULL might not seem optimal.

Ferruccio
+10  A: 

Bjarne Stroustrup discussing whether the delete operator should zero its operand. It's not the free() function, but it's a good discussion anyway. Consider points like:

  • What would be zeroed out if you said free(p + 1)?
  • What if there are two pointers to the memory? Why only set one to null if a dangling reference is still left behind?

He also says it was intended but never happened with operator delete:

C++ explicitly allows an implementation of delete to zero out an lvalue operand, and I had hoped that implementations would do that, but that idea doesn't seem to have become popular with implementers.
AshleysBrain
+3  A: 

With reference to the quote from Stroustrup about delete, Peter Norvig also makes a similar remark. He writes (not about C++!):

"Nothing is destroyed until it is replaced"
 - Auguste Comte (1798-1857) (on the need for revolutionary new
   theories (or on the need to do x.f = null in garbage-collected
   languages with destructors))

In my C code, I find the following macro very useful:

#define free(p) free((void *)(p)),(p)=NULL /* zero p */

This, as written, uses its argument twice. But this isn't a problem, as any usage such as free(p++) or free(find_named_object("foo")) will give a compile-time error (lvalue required). And you can hide the macro by using (free)(p++), or by calling it something else e.g. FREE.

Joseph Quinsey
If you have to remember to use a macro named `FREE` instead of just calling `free`, then why not just remember to null the pointer (if appropriate) instead ;p
Dan Moulding
I like it (I'm a sucker for syntactic sugar). But if someone else compiles one of your code snippets, thereby missing the #define, they may get unexpected behavior. +1 for the quote.
uncle brad
#define FREE(p) do { void** x = free(*x) ; *x = NULL } while(0)
JeremyP
`free(p++)` will *also* give a compile error, since the result of `p++` isn't an lvalue and can't be assigned to.
caf
@JeremyP: You can't take the address of the result of a cast operator, it's not an lvalue.
caf
@uncle brad: You are right. I actually use Free(), which is my wrapper to a wrapper hiding \_\_FILE\_\_ and \_\_LINE\_\_.
Joseph Quinsey
@caf: You are right about lvalues. I've modified my answer accordingly.
Joseph Quinsey
A: 

Casting the reference from int *& to void *& is not guaranteed to work. int * simply does not have to have the same size, representation nor alignment requirements as void *.

The proper C++ solution would be to use templates, as Neil Butterworth suggests in a comment. And neither of these ways work in C, obviously - which is where free() comes from.

caf
kriss
@kriss: `int *` and `void *` technically don't even have to have the same *size*. Casting `int *` to `void *` is OK, of course (`void *` must be able to represent every other pointer value).
caf
@caf: where did you got the size part ? I know of specific compilers extension for different kind of pointers of different size, but it works with qualifiers (far pointers, near pointer). Maybe some restriction in standard for function pointers ? However you could still use a `char *` instead of a `void *`, as it is what standard use for byte pointers.
kriss
@kriss: Simply that it isn't disallowed (in general) for the sizes to be different. In regards to `char *`, it is explicitly specified that: *A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.* - other than that, and a few other restrictions on pointers that must have the same representation and alignment requirements as each other, the representation (which includes the size) of pointers is left unspecified.
caf
A: 

What's this maniac thing with zero ? There are other numbers !

Why should a free pointer should contain zero more than any other distinguished value ?

Practically, in my C++ code I often use watchdog objects and when freeing a pointer reset it not to zero but to the watchdog. That has the added benefit that the methods of the object can still be called with the existing interface and is much more secure and efficient that resetting pointer to zero (it avoid testing objects for zero, I just call the object).

If a free like function say zfree(void * & p) would set p to zero it would forbid my watchdog style (or at least would'nt help).

And as others pointer out , what would be the point to reset a pointer to zero if it goes out of scope ? Just useless code. And what if there is other pointers that contain the same adress, etc.

kriss
There's no maniac obsession with zero. A constant expression with the value zero has a specific meaning, it is a null pointer constant. I think you've misunderstood the purpose of NULL (or 0). He's not proposing that the freed pointer contain zero, that is not what assigning 0 (or NULL) does; he's proposing setting its value to a null pointer value. A null pointer value is the only usable value that a pointer can contain if it does not point at an actual object so it is at least a plausibly sensible value to assign to a pointer that is no longer pointing at an object.
Charles Bailey
I disagree. A null pointer is not the only usable value that a pointer can contain if it does not point to an actual object. Any value that can't be allocated could be OK, and the compiler could ensure that such distinguished elements are not real address. But the main point is that the only use of this kind of zero is to know if a pointer is used or not. And there is many better methods (say smart pointer with a usage count, or watchdogs) to achieve that. Setting it to zero is one of the worst possible methods, making it default behavior would be even worse.
kriss
Perhaps I should have been clearer. In C, the valid values that a pointer can contain are a value obtained by taking the address of an object or one past the end of an array object or a null pointer value. Converting an integer to a pointer or address arithmetic are about the only other ways to give a pointer a value; in the first case you have no general guarantee that you won't generate a trap representation and in the latter case you must keep the result inside the array bounds of an array object otherwise you have undefined behaviour. Would you disagree with this?
Charles Bailey
I do not disagree with this. But nothing stop a compiler to reserve some legal addresses to be used as a distinguished element. You could call that allocate real objects if you want. But it's still easy. Also I worked with hardware where 0 was a perfectly valid address for an object (no trap nor anything special there). But the compiler took care that that part of memory wouldn't be accessible. Using zero for ensuring a pointer is not used is just convention, like using negative values for returning errors of functions like write().
kriss