Mabden said:
That's fine, but foo() should have a check like this, since you can't
use p if it's NULL:
void foo(int *p)
{
if (p == NULL) return;
}
Utter rubbish.
You *can* use `p` if it's NULL. You can, for example, compare it with a
pointer, pass it as a parameter, store it into a data structure, or return
it as a result. What you *cannot* do [1] is dereference it. In the OPs
example, they ignored it - doesn't look like that needs a check to me.
If you want to dereference it, then you have to decide what to do about
null pointers. Broadly speaking I see three choices:
(a) Declare that this function is undefined if p == 0. Any passing of
null is a user error. You don't need to check for null, since any
dereferencing gets you UB, and that's what you declared, but you
*can* check, and do whatever you like - eg log an error and exit,
log an error and don't exit, exploit some system-dependant exception
handler, whatever.
(b) Declare that p == 0 is illegal and define the error behaviour - such
as having an error code which takes distinct values on failure or
success, and performing the check. Or calling some error-handling
function ditto. Hard to do cleanly in the large.
(c) Declare that p == 0 is legal and has some special-case behaviour,
put in the appropriate check & code. EG one might (unsoundly, in
my view) decide that the string-length of (char *)0 was 0.
Saying the the only valid choice is (b) [and implying, albeit weakly,
that the recovery behaviour is "do nothing"] is ... unwise.
[My preferred choice is (a), if p doesn't express some notion of
"optional thingy", and (c) if it does, and (b) only if the other
two don't work. But I suspect that the weighting is very context-
sensitive.]
[1] If you prefer, you *can* do it, but to do so opens the way to demons,
so don't.