28

Many C code freeing pointers calls:

if (p)
  free(p);

But why? I thought C standard say the free function doesn't do anything given a NULL pointer. So why another explicit check?

CodingLab
  • 1,441
  • 2
  • 13
  • 37
zaharpopov
  • 16,882
  • 23
  • 75
  • 93

8 Answers8

27

The construct:

free(NULL);

has always been OK in C, back to the original UNIX compiler written by Dennis Ritchie. Pre-standardisation, some poor compilers might not have fielded it correctly, but these days any compiler that does not cannot legitimately call itself a compiler for the C language. Using it typically leads to clearer, more maintainable code.

17

As I understand, the no-op on NULL was not always there.

In the bad old days of C (back around 1986, on a pre-ANSI standard cc compiler) free(NULL) would dump core. So most devs tested for NULL/0 before calling free.

The world has come a long way, and it appears that we don't need to do the test anymore. But old habits die hard;)

http://discuss.joelonsoftware.com/default.asp?design.4.194233.15

Tom
  • 43,810
  • 29
  • 138
  • 169
  • 1
    +1 This is what I remember but I couldn't find the reference to it. – Matt Davis Dec 16 '09 at 04:45
  • As I understand it, this flaw existed in some compilers even after standardization. – Michael Burr Dec 16 '09 at 07:45
  • 1
    It was always there, even in the original UNIX implementation. This is mentioned in P.J. Plauger's article on the standardisation process - can't find exact reference at this moment though. –  Dec 16 '09 at 11:45
  • 3
    THe day that Joel is quoted as a technical authority is a sad one for the human race. –  Dec 16 '09 at 11:48
  • 1
    Neil: this is quote from the forum on joel website, actual quote not from him but someone named Guidii. so i think human race has been saved today – zaharpopov Dec 16 '09 at 13:10
  • Reciting Joel's uncited urban legend does not make a valid answer. – R.. GitHub STOP HELPING ICE May 21 '11 at 21:24
  • I wonder whether the requirement that `free(NULL)` does nothing ties in with the fact that `malloc(0)` is allowed to return `NULL`. IMHO, `malloc(0)` should have been allowed to return null on those systems, and only on those systems, where adding or subtracting integer `0` to/from a null pointer yields a null pointer (rather than UB), and `free(0)` does nothing, but having `free(0)` be safe on other systems isn't so important. – supercat Apr 17 '18 at 17:08
11

I tend to write "if (p) free(p)" a lot, even if I know it's not needed.

I partially blame myself because I learned C the old days when free(NULL) would segfault and I still feel uncomfortable not doing it.

But I also blame the C standard for not being consistent. Would, for example, fclose(NULL) be well defined, I would not have problems in writing:

free(p);
fclose(f);

Which is something that happens very often when cleaning up things. Unfortunately, it seems strange to me to write

free(p);
if (f) fclose(f);

and I end up with

if (p) free(p);
if (f) fclose(f);

I know, it's not a rational reason but that's my case :)

Remo.D
  • 16,122
  • 6
  • 43
  • 74
  • Yes, this answer pin points the lack of consistency in C and it is in fact overhead on the programmer to track the proper practices. – aashima May 09 '21 at 14:15
3

Compilers, even when inlining are not smart enough to know the function will return immediately. Pushing parameters etc on stack and setting the call up up is obviously more expensive than testing a pointer. I think it is always good practice to avoid execution of anything, even when that anything is a no-op. Testing for null is a good practice. An even better practice is to ensure your code does not reach this state and therefore eliminate the need for the test altogether.

Anonymous
  • 39
  • 1
2

There are two distinct reasons why a pointer variable could be NULL:

  1. because the variable is used for what in type theory is called an option type, and holds either a pointer to an object, or NULL to represent nothing,

  2. because it points to an array, and may therefore be NULL if the array has zero length (as malloc(0) is allowed to return NULL, implementation-defined).

Although this is only a logical distinction (in C there are neither option types nor special pointers to arrays and we just use pointers for everything), it should always be made clear how a variable is used.

That the C standard requires free(NULL) to do nothing is the necessary counterpart to the fact that a successful call to malloc(0) may return NULL. It is not meant as a general convenience, which is why for example fclose() does require a non-NULL argument. Abusing the permission to call free(NULL) by passing a NULL that does not represent a zero-length array feels hackish and wrong.

dpi
  • 1,919
  • 17
  • 17
0

If you rely on that free(0) is OKAY, and it's normal for your pointer to be null at this point, please say so in comment // may be NULL

This may be merely self-explanatory code, saying yes I know, I also use p as a flag.

Pavel Radzivilovsky
  • 18,794
  • 5
  • 57
  • 67
0

there can be a custom implementation of free() in mobile environment. In that case free(0) can cause a problem. (yeah, bad implementation)

CodingLab
  • 1,441
  • 2
  • 13
  • 37
  • 3
    A new C implementation, when started today, has no excuse for producing such a bug. The C standards are clear in that point. – vog Dec 23 '10 at 14:02
  • 1
    @vog: Freestanding implementations aren't required to provide `malloc()` and `free()` at all, but will typically allow user code to define such functions as they see fit. Including an explicit null-check will make code work even in the presence of `#define free(x) customReleaseThatDoesntLikeNull(x)`. – supercat Apr 17 '18 at 17:10
0
if (p)
    free(p);

why another explicit check?

If I write something like that, it's to convey the specific knowledge that the pointer may be NULL...to assist in readability and code comprehension. Because it looks a bit weird to make that an assert:

assert(p || !p);
free(p);

(Beyond looking strange, compilers are known to complain about "condition always true" if you turn your warnings up in many such cases.)

So I see it as good practice, if it's not clear from the context.

The converse case, of a pointer being expected to be non null, is usually evident from the previous lines of code:

...
Unhinge_Widgets(p->widgets);
free(p); // why `assert(p)`...you just dereferenced it!
...

But if it's non-obvious, having the assert may be worth the characters typed.