NULL Pointers in C
In C language, an uninitialized pointer contains a random memory address, which could be valid or not. To indicate that a pointer does not point to any memory location, we can assign it the special value NULL. In this lesson we will see how to use the NULL pointer and how to verify if a pointer is valid or not.
Uninitialized Pointers
We have seen, in previous lessons, that when we declare but do not initialize a pointer in C language, it points to any memory location.
int *p;
In this case, the pointer p points to any memory location, which could be a valid memory location or not. If we try to access that memory location, we could get a segmentation error, or we could get a random value.
int *p;
*p = 5; // Segmentation error
The point is that the memory address to which the pointer p points is random.
At first glance, this behavior might seem strange, if not absurd. The reality is that the C language standard does not require that a pointer, as well as any other type of variable, be initialized with a known value, at declaration time.
The same happens, for example, with integer variables:
int x;
printf("%d\n", x); // Random value
In this case, the variable x has not been initialized, and the value we get is random. It does not necessarily contain the value 0.
But why is the value random?
The answer is that, when the program starts, the operating system assigns a memory block to the program, and the C compiler does not add code to clean the assigned memory. Therefore, the value of an uninitialized variable is the value that was already in that memory location. In other words, the memory could have already been dirtied by another program previously running.
Other programming languages automatically add, without the programmer requesting it, code routines that, at startup time, initialize variables with known values.
In C this does not happen and it is the programmer's responsibility to provide for the initialization of variables.
Invalid Pointers: NULL
The consequence of what was said above is that an uninitialized pointer contains anyway a memory address that, being random, could point to a valid memory location or not.
In a sense, therefore, there is no invalid pointer in the strict sense. That is, a pointer that points to nothing.
For example, if we execute the following code:
int *p;
if (p) {
/* ... */
}
The condition inside the if statement will result surprisingly true! Even if the pointer p has not been initialized. This is because the address inside it will be, in most cases, different from zero and for the if statement this is equivalent to true.
How can we, then, distinguish if a pointer is valid or not, that is, if it points to something or to nothing? Can we assign an invalid value to a pointer to indicate that it does not point to any memory location?
The answer is yes. In C, there is a special value that we can assign to a pointer to indicate that it does not point to any memory location. This value is NULL.
int *p = NULL;
if (p == NULL) {
printf("The pointer p does not point to any memory location\n");
}
The value NULL should be understood as a special value that indicates a nonexistent memory location.
It is, in all respects, a macro that translates to a numeric value, which is generally 0.
The NULL macro is defined in various header files of the C standard library, some of which are:
stdio.hstdlib.hstring.htime.hstddef.h
Therefore, to use the NULL macro, it is necessary to include at least one of them.
NULL Pointer
The NULL macro is a special value that can be assigned to a pointer to indicate that it does not point to any memory location.
Validity Test of a Pointer
Many functions, even from the standard library, return pointers.
There could be cases where the invoked function cannot return a valid pointer. We will explore this behavior in the next lessons. Very often, in these cases, library functions return NULL precisely to indicate that it was not possible to return a valid pointer.
Therefore, it is always good programming practice, whenever a pointer is received from a function, to verify if it is valid or not.
To do this, in C language, there are various ways, but the best one is the following:
int *p = function();
if (p == NULL) {
printf("Error: the function did not return a valid pointer\n");
}
else {
/* ... */
}
In this way the returned pointer is explicitly compared with the value NULL.
In many programs, however, comparisons of this type are often found:
int *p = function();
if (!p) {
printf("Error: the function did not return a valid pointer\n");
}
else {
/* ... */
}
Since NULL translates in most systems to the value 0, the comparison if (!p) is equivalent to if (p == NULL).
Even, in certain programs the direct comparison with 0 is performed:
int *p = function();
if (p == 0) {
printf("Error: the function did not return a valid pointer\n");
}
else {
/* ... */
}
These last two forms of comparison, however, should be avoided, as they are less explicit and less readable.
Verification of a Pointer
When you want to verify if a pointer is valid or not, it is good practice to compare it with the value NULL:
if (p == NULL) {
/* ... */
}
In Summary
In this lesson we introduced the NULL pointer:
- We saw that an uninitialized pointer contains a random memory address, which could be valid or not.
- We introduced the special value
NULL, which indicates that a pointer does not point to any memory location. - We saw how to verify if a pointer is valid or not.
In the next lesson we will study another important type of pointer: the void pointer.