a value indicating that a pointer does not refer to a valid object
Videos
What is the purpose of a null pointer in programming?
Can a null pointer be assigned to any data type?
What is the difference between a null pointer and an uninitialized pointer?
Hello all again,
I have another stupid question here lol, so I'm trying to wrap my head around NULL. Im currently under the impression that NULL is a built in constant that has a value of zero, but what does that actually mean? When would it be appropriate to use null? If someone could explain it in layman's terms that would be super helpful!
The 0xCACACACA generated by Visual Studio is usually there for un-initialized pointers, for precisely this reason. When you see this, you know something is wrong. If it initialized it to 0, it can very well be expected behavior. This is only done in debug node, with full optimization the value of an uninitialized pointer would be just garbage.
And yes, NULL pointers don't have a value of 0 per say. 0 is just a literal. The actual value can be different. But the compiler is smart enough to abstract that away, so even if you have a NULL pointer whose value isn't really 0 (as in the number 0), comparing it to 0 or NULL would still yield true. It's better to think in terms of nullptr really.
This question previously appeared on the comp.lang.c newsgroup. You can read the archive with Google Groups
In that thread, Paul Sand quoted another source, "Portable C" by H. Rabinowitz and Chaim Schaap, as follows:
Certain Prime computers use a value different from all-bits-0 to encode the null pointer. Also, some large Honeywell-Bull machines use the bit pattern 06000 to encode the null pointer. On such machines, the assignment of
0to a pointer yields the special bit pattern that designates the null pointer.Similarly,
(char *)0yields the special bit pattern that designates a null pointer.
Where you'd commonly see non-null pointers is when working with physical memory addresses (that is, when there is no MMU or in kernel mode bypassing the MMU) and the machine has memory-mapped I/O at or near address 0. You want a null pointer to be way out in no-man's land, so that if you offset it (e.g. structure member access via a pointer) you won't get any useful address.
For your specific question, only an integral constant expression with value 0 is interpreted as a null pointer. So
char* p = (char*)i;
does not portably make p a null pointer (i.e. the Standard makes no such guarantee, but your particular compiler may).
The definition of NULL is a syntactic crutch to allow a programmer a clear expression that a pointer is, at certain times, pointing nowhere. It's meant for readability - and with increased compiler bloat even for automated checks.
On a hardware level there is no such thing. A pointer is a word, and a word always holds a valid number. So by convention zero was chosen - it could have been any other. Like -1 for example. Selecting 0 offered the advantage that a simple if(pointer) could be used to check if it's a valid pointer (or more correct, not 0).
So my question is what led some C standard to treat the NULL pointer differently from any other pointer?
C also doesn't treat NULL different from any other pointer. The C library in contrast does, but not because of NULL, but rather as its (runtime) value of 0 will make some functions fail, when used as input.
Did K&R want to target an exotic architecture or something?
No. It's a concept needed from a pure software engineering point of view. Having a syntactic construct to handle uninitialized pointers improves readability and possibly enables further checks.
Now, for the historic part, NULL is, like the related handling of TRUE/FALSE inherited from BCPL (through B). Just here it was called nil.
Even with that little historic bit, I'm not sure if Retrocomputing is the right place to ask for this, as it's about a basic concept in software engineering and not anything burdened with historic implication. So a quick search in Software Engineering and Stack Overflow shows that this question has been asked many times. It's something people always stumble on, isn't it?
The important thing you may be missing is that a null pointer in C is not required by the standard to have the same binary representation as the number zero. It is still a "normal" pointer, but it points to a special location that the program is not allowed to use.
The integer constant 0 is turned into nullptr when used as a pointer. Similarly, 0 will become 0.0 when used in floating-point calculations, or false in boolean operations. Coercions are not just one-way: if(ptr) will convert a pointer into a boolean which indicates whether the pointer is not null. All of these conversions serve to avoid requiring that a null pointer shares the same representation as zero.
Most machines represent integer zero as all-bits-zero and comparisons against that are particularly cheap, so it is worthwhile to arrange things so that sentinel values such as null pointers and end-of-string markers are all-bits-zero, and also that +0.0 and false are also all-bits-zero.
There is some subtlety in C in that a literal 0 is converted into nullptr, whereas casting an integer that happens to be zero into a pointer will produce a pointer to location zero. Because they are the same thing on modern platforms, a whole class of potential bugs go away.