9

I always thought that C does not accept NULL parameters, until I started learning about pointers. In some programming languages, like python for one, it is possible to pass a NULL parameter as an argument, but in C I always thought this would result in Undefined Behaviour.

My question is just one of curiosity, how can a function, such as this...

waitpid(child_pid, &status, options);  //pointer &status

...accept a NULL pointer as parameter without running into Undefined Behaviour, don't NULL pointers simply point to nothing?

Simply put, why is this acceptable in C?

buydadip
  • 8,890
  • 22
  • 79
  • 154
  • It depends on how the function was written. If there is a behaviour associated with a NULL pointer, why would it be undefined behaviour? – AntonH Dec 17 '14 at 18:35
  • I would say it is desirable, if you want to have invalid pointers. – Iharob Al Asimi Dec 17 '14 at 18:35
  • If you dereference the null pointer in the called function, it does lead to undefined behaviour. Code that is designed to accept a null pointer will have code that tests whether the pointer is null before using it. In `waitpid()`, for example, the pointer might be `int *statloc` and the code might be `if (statloc != NULL) *statloc = status;`. – Jonathan Leffler Dec 17 '14 at 18:36
  • What do you mean exactly by "NULL non-pointer values"? – Codor Dec 17 '14 at 18:37
  • @Codor Ill re-edit, just ignore that part, I just want to know why it is acceptable in C to pass a NULL parameter – buydadip Dec 17 '14 at 18:41
  • 1
    It is pointing to NULL, the pointer itself is not NULL. The pointer has an address. But it is not pointing to another address when set to NULL. – Morpfh Dec 17 '14 at 18:41
  • NULL is just another value that you can pass in. – Gophyr Dec 17 '14 at 18:56
  • In some languages, often ones that pass around type information along with values, there's a NULL type that indicates the absence of a value (a variable that hasn't been set to anything). C doesn't have this; NULL in C is just for pointers, and is just a reserved value for pointers that aren't pointed to an actual object. – Dmitri Dec 17 '14 at 18:58
  • 1
    There is a couple of other Q/A that you also might find helpful. (Somewhat in the same genre.): http://stackoverflow.com/q/11962457/1240985 , http://stackoverflow.com/q/6725809/1240985 , http://stackoverflow.com/a/1597486/1240985 – Morpfh Dec 17 '14 at 19:40

4 Answers4

9

In some programming languages [...] it is possible to pass a NULL parameter as an argument, but in C I always thought this would result in Undefined Behavior.

Passing a NULL parameter for a pointer by itself does not result in UB; it's attempting to access the memory pointed to by a pointer set to NULL that does.

Passing NULL is a very common practice for situations when something is not specified. The caller is expected to check parameters for NULL before performing the access. For example, the standard lets you pass NULL to free, which makes the function a lot more convenient.

don't NULL pointers simply point to nothing?

Yes, they do. But that "nothing" is globally well-known, so using a NULL lets you communicate the fact that a pointer points to nothing to functions that you call. In other words, the check

if (myPointer == NULL)

is well-defined*, so you can use it to your advantage.

* Unless you use a dangling pointer, i.e. a pointer that you have freed, or a pointer that points to object that went out of scope. You can prevent the first situation from happening by assigning NULL to every pointer that you free(), and the second situation by declaring pointers in the scope that has the same or higher level of nesting as the scope of an automatic object to which the pointer is pointing.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    "is always well-defined,"-I think this is not true. Check the answer here http://stackoverflow.com/questions/26073842/is-the-compiler-allowed-to-recycle-freed-pointer-variables, please – Giorgi Moniava Dec 17 '14 at 18:53
  • @giorgim You are right, I made an assumption that the pointer is valid. I explained this assumption in a footnote. Thanks! – Sergey Kalinichenko Dec 17 '14 at 19:00
  • glad it helped;that is tricky one. It's not intuitive why just checking would be UB, but what can you do :( – Giorgi Moniava Dec 17 '14 at 19:04
4
void func_with_optional_arg(char *optional)
{
    if (optional == NULL) {
        // do something differently
    }

    /* ... */
}

Why would that invoke UB? Dereferencing a NULL pointer certainly would, but passing one around does not. NULL is a sentinel value used to determine whether or not a pointer is valid (not that invalid pointers cannot have other values, but we use this one explicitly.) If passing it to a function invoked UB then what would be the point of its existence in the first place?

whereas passing a NULL non-pointer value is not?

There is no such thing as a "NULL non-pointer" in C, so I'm not sure what you mean here.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • :Your if statement would already invoke UB if pointer was passed to it after it was freed :) – Giorgi Moniava Dec 17 '14 at 18:41
  • @giorgim: That is not true at all. The pointer is not being dereferenced, we're only comparing its value, which is perfectly legal pre- or post-`free`. Besides, there are all sorts of ways to invoke UB that cannot be accounted for from within a called function. – Ed S. Dec 17 '14 at 18:43
  • 1
    I think you are mistaken, please see the answer here: http://stackoverflow.com/questions/26073842/is-the-compiler-allowed-to-recycle-freed-pointer-variables – Giorgi Moniava Dec 17 '14 at 19:08
  • 1
    @giorgim: Huh. Ten years of writing C and I'm still learning new things. I suppose it is a valid case for optimization. Good thing it's not something I've ever felt the need to do in real code. Thanks. – Ed S. Dec 17 '14 at 19:09
1

Because a function can check if the pointer is NULL and avoid using it. A classic example is a function that returns something as a return value, and can provide some additional information through a pointer parameter. If the caller is not interested in such information (and the callee is prepared for this) the pointer parameter is set to NULL, and the called function won't try to store anything in the location pointed by it.

int divide(int dividend, int divisor, int *remainder=NULL) 
{
    if(remainder!=NULL) 
        *remainder=dividend%divisor;
    return dividend/divisor;
} 

waitpid follows this idiom: if you don't care about the status, you can pass NULL, avoiding a dummy variable.

In general, you can use NULL as a special value to signify that no valid pointer has been passed; another common usage is to say "use a default value" for some pointer parameter.

Notice that this isn't much different from Python: you can't do much on a None without getting an error, but you can always check if a value is None and act accordingly.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
0

It all depends on how you deal with NULL. Essentially NULL represents a value of 0, thus if you try to use it as an integer you shouldn't have any problems. BUT keep in mind that NULL is a define to represent invalid memory position (inexistent) and not to be used as an integer!

For pointers, on the other hand, it is important to verify whether the pointer points to a valid address. Usually functions that accept pointers must verify if the value passed is valid, otherwise it'll end up trying to access some invalid memory position and crashing.

delirium
  • 868
  • 6
  • 20
  • How would a function test whether a pointer passed in points to valid memory? – alk Dec 17 '14 at 18:54
  • 2
    It depends on how deep you want your answer. For the sake of simplicity, what I meant is to verify whether a pointer is NULL or not. Other than that, **one cannot check whether a pointer is valid or not**! If you're working at an embedded system, knowing all memory positions and etc (full system access), THEN you might guarantee a valid memory position!! – delirium Dec 17 '14 at 18:59