NULL breaks the type system. Now every pointer type is actually two types: the normal type, and the NULL type. You can dereference or call methods on one, but not the other, and only a runtime check will tell you what you're dealing with. Any time you see:
Object *
You cannot read that as "pointer to Object." You have to read it as "pointer to Object, or NULL."This causes three big problems. One is that it's way too easy to forget to check for NULL. The second, related problem is that without a way to express a non-nullable pointer type, you have to rely on documentation and convention to express the difference. The third is that since only pointer types are nullable, you have to reinvent the wheel any time you you want to express the concept of "null" for a non-pointer type.
To illustrate, you point out malloc which returns NULL when it runs out of address space. What's the appropriate return type?
void *
Now let's say you had some other memory allocation call which could never return failure to the caller. Maybe it aborts execution on failure, or maybe it retries continually until memory becomes available. What's the appropriate return type? void *
Oops. Same problem with parameters. Here's a function: void f(void *ptr)
Are you allowed to pass NULL? Who knows, go RTFM. If the answer is "no," what happens if you pass NULL anyway? The compiler certainly won't catch it, and who knows what will happen.NULL is "just a tool" but it's not a very good tool. It breaks the type system in a fundamental and painful way.
Edit: whew, HN's markup makes it kind of hard to talk about C pointers!