Why can pointers be NULL - c++

In C or C++, isn't NULL just the constant integer 0? Why are we allowed to assign some pointer to the value NULL if it a constant integer? Wouldn't a compiler say that the two types don't match?

The interpretation of the constant 0 depends on the context. If it's being used in a context where a number is required, it's the number zero. If it's being used in a context where a pointer is required, it's treated as a null pointer. So if you have the code:
int n = 0; // assigns zero
int *p = 0; // assigns null pointer
somefunc((char *)0); // passes null pointer to the function
In C, the macro NULL is permitted to expand into either an integer constant 0 or such a constant cast to void *. In C++ pre-11, it can expand into either an integer constant that evaluates to 0. In C++-11 it can expand into an integer literal with value 0 or a prvalue of type std::nullptr_t (e.g. nullptr).
See http://en.cppreference.com/w/cpp/types/NULL for the C++ description, http://en.cppreference.com/w/c/types/NULL for the C description.

There are two issues:
A type can have a "special", out-of-band, exceptional value. For example, floating-point numbers have the value NaN. And pointers have a special, not-a-valid-pointer value, the null pointer.
What's the name of the null pointer? In C, for better or worse, its name is 0. (It would avoid all kinds of confusion if its name were a separate keyword like null or nil, but that's not the way the language definition came out.)
But yes, you're right, the ability to assign the constant 0 to a pointer variable is a special case, enshrined in the language definition.

6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
C 2011 online draft
A literal 0 in a pointer context is treated specially by the compiler, and is understood to be the null pointer constant. In the context of your source code, it behaves like any other zero-valued expression.
However, once your code is translated to machine code, all occurrences of the null pointer constant will be replaced with whatever value the underlying platform uses to represent a well-defined invalid pointer value, whether that’s 0 or 0xFFFFFFFF or 0xDEADBEEF.

Related

What happens we create a nullptr and use it in a IF condition in C++

Hi i am trying to see what happens when i create a nullptr in C++ and use it in a if statement. For example, my code is as following:
int *p=nullptr; if(p){cout<<"Inside IF";}
My questions are as follows:
What happens when we create a nullptr? I mean does a new pointer object is created that holds the value 0(as address) or something else? And if the address it holds is 0 then is that pointer pointing to a possibly valid address in the memory?
What is happening when we use it in the IF statement ? I mean is the IF statement checking whether the value that the pointer object holds is 0 or something else?
What happens when we create a nullptr?
You can create a null pointer, but not a nullptr. The keyword nullptr denotes a literal value, not something that can be created.
Based on your code, you meant to ask what happens when a pointer variable is assigned nullptr. The answer to that is that your variable becomes a null pointer, a pointer that points to nothing and that evaluates to false when used in a boolean context.
I mean does a new pointer object is created that holds the value 0(as address) or something else?
We usually think of the value of a null pointer as being zero, but technically an implementation could use a bit pattern that has some non-zero bits. As long as you do not look too closely at the compiled code, go ahead and think of null pointers as holding the address 0.
And if the address it holds is 0 then is that pointer pointing to a possibly valid address in the memory?
The value of a null pointer must be distinct from all potentially valid memory addresses. If 0 is possibly a valid memory address in an implementation, then that implementation must use a different bit pattern to represent null pointers. (I am not aware of any implementations that fall into this category.)
What is happening when we use it in the IF statement ?
The condition of an if statement is contextually converted to bool. When converting to bool from a pointer, the null pointer value converts to false and all other values convert to true.
I mean is the IF statement checking whether the value that the pointer object holds is 0 or something else?
Something else (but only by a fine shade of meaning). It checks whether the value is the null pointer value (which is almost certainly represented by zero bits on your computer, but technically not guaranteed to be so).
What you said is right nullptr allocates location and gives value 0 and 0 is false in c++
#include <iostream>
using namespace std;
int main() {
int *p=nullptr;
if(p){cout<<"Inside IF";}
cout<<&p<<endl;
cout<<p;
}
Output
0x7ffc92b66710
0
For reference:
nullptr, the null pointer literal
std::nullptr_t, the type of nullptr
implicit conversions, particularly pointer to bool conversions.
The line
int *p=nullptr;
Creates an int* pointer-to-int with automatic storage duration. Then nullptr is assigned to it, and is automatically converted to the null pointer value for the int* pointer. It's not actually necessarily the case that this value is stored internally as 0, although there's an implicit conversion from the integer literal 0 to the null pointer value for every pointer type.
Then, in the comparison
if(p){cout<<"Inside IF";}
There's an implicit conversion from every pointer type to bool, which is applied in this if statement. Specifically:
Boolean conversions
The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.
So p has the value of the null int* pointer, and therefore becomes false.

Difference Between NULL and Zero in Comparing

I know a little bit about NULL, but when it comes to comparing I get confused.
For Example:
int* p;
if(p == NULL){
//do stuff
}
if(p == 0){
//do stuff
}
In the first comparison "p" compares with what address?
Is it looking for the reference point of "p", and seeing if it is valid or not?
In every modern implementation of C, NULL is zero, usually as a pointer value:
#define NULL (void *) 0
So comparing, say, a character to NULL is likely to be invalid:
char ch = 'a';
if (ch == NULL) // probably "invalid comparison of pointer with scalar"
As a pointer value, NULL chosen to point to invalid memory so that dereferencing it (on a suitable architecture) will cause a memory fault. Most virtual machines reserve lower memory just for this purpose and implemented by leaving low memory unmapped to physical memory. How much memory is unreserved? Could be a few kilobytes, but many implementations reserve a few megabytes.
NULL represents a value that is not used by any valid pointer. So, if a pointer is NULL, it points to no variable at all. In pointer contexts, the value zero means the same thing as NULL, however it is clearer to use NULL instead of zero. That's all you need to know about NULL.
From the C99 Standard:
7.17 Common definitions <stddef.h>
3 The macros are
NULL
which expands to an implementation-defined null pointer constant; ...
From the C++11 Standard:
18.2 Types
3 The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).194
Footnote 194:
194) Possible definitions include 0 and 0L, but not (void*)0.
Microsoft VS 2008 defines it as:
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
gcc/g++ 4.9.3 defines it as:
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and <stddef.h> or need NULL. */
I suspect other modern compilers define it similarly.
Given the above definitions of NULL, the line
if(p == NULL){
expands to:
if(p == ((void*)0) ){
in C.
It expands to
if(p == 0){
in C++.
In other C++ compilers, that line could expand to
if(p == 0L){
When using C++11, it is better to avoid NULL and start using nullptr instead.
if ( p == nullptr ) {
Conceptually, NULL is a singular pointer-value pointing nowhere, and implicitly convertible to any pointer-type.
Practically, you unfortunately cannot depend on it behaving as a pointer value unless you use it in a pointer-only context.
Thus, use nullptr in C++11 and later respectively 0 cast to the right pointer-type, especially in contexts where an integral zero would not be converted to a pointer.
BTW: While on most modern systems a null pointer is really all-bits-zero, that's not required by the standard (there might be many bit-patterns representing null pointers, and none all-zero), and doesn't make any difference to how a null pointer constant is represented in source code.
In C++:
The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).
Which is defined as:
A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t.
Pre-C++11 the last option was obviously not available...
And post-C++11, because you do not know what it is, you should use nullptr directly.
In C:
The macros are
NULL
which expands to an implementation-defined null pointer constant; ...
Which is defined as:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
NULL in C++ compilers is just a macro defining a "null pointer constant" (generally of value 0). So there is no difference, apart from NULL being used to indicate an intent (which is important). For example you can create an int variable with the value NULL, which is not given any special treatment over the standard declaration (int a = 0;).
NULL is NOT "an empty space in memory". It is just a symbol that (generally) represents an absence of something (value, pointer etc...).
However using of NULL is now discouraged in C++ and the far superior nullptr should be used instead.
know that NULL is a empty space in memory
Not quite - NULL is a well-defined "nowhere" that doesn't correspond to any valid memory address.
In both C and C++, the NULL macro is defined to be a null pointer constant, which is a zero-valued integer expression. C++ also provides the nullptr literal, which also evaluates to the null pointer constant. When a null pointer constant appears in a pointer context, it will be converted to an implementation-defined null pointer value. A null pointer value may or may not be 0-valued, but it is guaranteed to compare unequal to any valid pointer value.
C 2011 online standard:
6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.
66) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
66)) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19
C++ 2014 online draft
2.13.7 Pointer literals [lex.nullptr]
pointer-literal:
nullptr
1 The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t. [Note: std::nullptr_t
is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is
a null pointer constant and can be converted to a null pointer value or null member pointer value. See 4.10
and 4.11. — end note ]
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type
and is distinguishable from every other value of object pointer or function pointer type. Such a conversion
is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The
conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the
sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of
integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a
null pointer value. — end note ]
...
18.2 Types [support.types]
...
3 The macro NULL is an implementation-defined C++ null pointer constant in this International Standard
(4.10).194
194) Possible definitions include 0 and 0L, but not (void*)0
To hammer some points home:
The NULL macro, nullptr literal (C++ only), and null pointer constant are always 0-valued;
The null pointer value does not have to be 0-valued;
The null pointer value will never equal a valid memory address;
It's the compiler's job to map the null pointer constant in your source code to the equivalent null pointer value in the generated machine code; as the programmer, you don't (generally) need to worry about the actual null pointer value on your implementation;
Since a null pointer constant is always 0-valued, comparing a pointer value against 0 should be equivalent to comparing it against NULL or nullptr.

How to write C/C++ code correctly when null pointer is not all bits zero

As the comp.lang.c FAQ says, there are architectures where the null pointer is not all bits zero. So the question is what actually checks the following construction:
void* p = get_some_pointer();
if (!p)
return;
Am I comparing p with machine dependent null pointer or I'm comparing p with arithmetic zero?
Should I write
void* p = get_some_pointer();
if (NULL == p)
return;
instead to be ready for such architectures or is it just my paranoia?
According to the C spec:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant. 55) If a null
pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.
So 0 is a null pointer constant. And if we convert it to a pointer type we will get a null pointer that might be non-all-bits-zero for some architectures. Next let's see what the spec says about comparing pointers and a null pointer constant:
If one operand is a
pointer and the other is a null pointer constant, the null pointer
constant is converted to the type of the pointer.
Let's consider (p == 0): first 0 is converted to a null pointer, and then p is compared with a null pointer constant whose actual bit values are architecture-dependent.
Next, see what the spec says about the negation operator:
The result of the logical negation operator ! is 0 if the value of its
operand compares unequal to 0, 1 if the value of its operand compares
equal to 0. The result has type int. The expression !E is equivalent
to (0==E).
This means that (!p) is equivalent to (p == 0) which is, according to the spec, testing p against the machine-defined null pointer constant.
Thus, you may safely write if (!p) even on architectures where the null pointer constant is not all-bits-zero.
As for C++, a null pointer constant is defined as:
A null pointer constant is an integral constant expression (5.19)
prvalue of integer type that evaluates to zero or a prvalue of type
std::nullptr_t. A null pointer constant can be converted to a pointer
type; the result is the null pointer value of that type and is
distinguishable from every other value of object pointer or function
pointer type.
Which is close to what we have for C, plus the nullptr syntax sugar. The behavior of operator == is defined by:
In addition, pointers to members can be compared, or a pointer to
member and a null pointer constant. Pointer to member conversions
(4.11) and qualification conversions (4.4) are performed to bring them
to a common type. If one operand is a null pointer constant, the
common type is the type of the other operand. Otherwise, the common
type is a pointer to member type similar (4.4) to the type of one of
the operands, with a cv-qualification signature (4.4) that is the
union of the cv-qualification signatures of the operand types. [ Note:
this implies that any pointer to member can be compared to a null
pointer constant. — end note ]
That leads to conversion of 0 to a pointer type (as for C). For the negation operator:
The operand of the logical negation operator ! is contextually
converted to bool (Clause 4); its value is true if the converted
operand is true and false otherwise. The type of the result is bool.
That means that result of !p depends on how conversion from pointer to bool is performed. The standard says:
A zero value, null pointer value, or null member pointer value is
converted to false;
So if (p==NULL) and if (!p) does the same things in C++ too.
It doesn't matter if null pointer is all-bits zero or not in the actual machine. Assuming p is a pointer:
if (!p)
is always a legal way to test if p is a null pointer, and it's always equivalent to:
if (p == NULL)
You may be interested in another C-FAQ article: This is strange. NULL is guaranteed to be 0, but the null pointer is not?
Above is true for both C and C++. Note that in C++(11), it's preferred to use nullptr for null pointer literal.
This answer applies to C.
Don't mix up NULL with null pointers. NULL is just a macro guaranteed to be a null pointer constant. A null pointer constant is guaranteed to be either 0 or (void*)0.
From C11 6.3.2.3:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant 66). If a null
pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
7.19:
The macros are
NULL
which expands to an implementation-defined null pointer constant;
Implementation-defined in the case of NULL, is either 0 or (void*)0. NULL cannot be anything else.
However, when a null pointer constant is assigned to a pointer, you get a null pointer, which may not have the value zero, even though it compares equal to a null pointer constant. The code if (!p) has nothing to do with the NULL macro, you are comparing a null pointer against the arithmetic value zero.
So in theory, code like int* p = NULL may result in a null pointer p which is different from zero.
Back in the day, STRATUS computers had null pointers as 1 in all languages.
This caused issues for C, so their C compiler would allow pointer comparison of 0 and 1 to return true
This would allow:
void * ptr=some_func();
if (!ptr)
{
return;
}
To return on a null ptr even though you could see that ptr had a value of 1 in the debugger
if ((void *)0 == (void *)1)
{
printf("Welcome to STRATUS\n");
}
Would in fact print "Welcome to STRATUS"
If your compiler is any good there are two things (and only two things) to watch out for.
1: Static default initialized (that is, not assigned) pointers won't have NULL in them.
2: memset() on a struct or array or by extension calloc() won't set pointers to NULL.

Can the expression "(ptr == 0) != (ptr == (void*)0)" really be true?

I read this claim in a forum thread linked to in a comment by #jsantander:
Keep in mind that when you assign or compare a pointer to zero, there is some special magic that occurs behind the scenes to use the correct pattern for the given pointer (which may not actually be zero). This is one of the reasons why things like #define NULL (void*)0 are evil – if you compare a char* to NULL that magic has been explicitly (and probably unknowingly) turned off, and an invalid result may happen. Just to be extra clear:
(my_char_ptr == 0) != (my_char_ptr == (void*)0)
So the way I understand it, for an architecture where the NULL pointer is, say, 0xffff, the code if (ptr), would compare ptr to 0xffff instead of to 0.
Is this really true? Is it described by the C++ standard?
If true, it would mean that 0 can be safely used even for architectures that have a non-zero NULL pointer value.
Edit
As an extra clarification, consider this code:
char *ptr;
memset(&ptr, 0, sizeof(ptr));
if ((ptr == (void*)0) && (ptr != 0)) {
printf("It can happen.\n");
}
This is how I understand the claim of this forum post.
There's two parts to your question. I'll start with:
If true, it would mean that 0 can be safely used even for architectures that have a non-zero NULL pointer value.
You are mixing up "value" and "representation". The value of a null pointer is called the null pointer value. The representation is the bits in memory that are used to store this value. The representation of a null pointer could be anything, there is no requirement that it is all-bits-zero.
In the code:
char *p = 0;
p is guaranteed to be a null pointer. It might not have all-bits-zero.
This is no more "magic" than the code:
float f = 5;
f does not have the same representation (bit-pattern in memory) as the int 5 does, yet there is no problem.
The C++ standard defines this. The text changed somewhat in C++11 with the addition of nullptr; however in all versions of C and C++, the integer literal 0 when converted to a pointer type generates a null pointer.
From C++11:
A null pointer constant is an integral constant expression prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion.
0 is a null pointer constant, and (char *)0 for example is a null pointer value of type char *.
It's immaterial whether a null pointer has all-bits-zero or not. What matters is that a null pointer is guaranteed to be generated when you convert an integral constexpr of value 0 to a pointer type.
Moving onto the other part of your question. The text you quoted is complete garbage through and through. There's no "magic" in the idea that a conversion between types results in a different representation, as I discuss above.
The code my_char_ptr == NULL is guaranteed to test whether or not my_char_ptr is a null pointer.
It would be evil if you write in your own source code, #define NULL (void*)0. This is because it is undefined behaviour to define any macro that might be defined by a standard header.
However, the standard headers can write whatever they like so as the Standard requirements for null pointers are fulfilled. Compilers can "do magic" in the standard header code; for example there doesn't have to be a file called iostream on the filesystem; the compiler can see #include <iostream> and then have hardcoded all of the information that the Standard requires iostream to publish. But for obvious practical reasons, compilers generally don't do this; they allow the possibility for independent teams to develop the standard library.
Anyway, if a C++ compiler includes #define NULL (void *)0 in its own header, and as a result something non-conforming happens, then the compiler would be non-conforming obviously. And if nothing non-conforming happens then there is no problem.
I don't know who the text you quote would direct its "is evil" comment at. If it is directed at compiler vendors telling them not to be "evil" and put out non-conforming compilers, I guess we can't argue with that.
I think the forum post you link to is incorrect (or we have misinterpreted what it means by !=). The two sub-expressions have different semantics but the same result. Assuming that my_char_ptr really has type char* or similar, and a valid value:
my_char_ptr == 0 converts 0 to the type of my_char_ptr. That yields a null pointer because 0 is an example of a so-called "null pointer constant", which is defined in the standard. It then compares the two. The comparison is true if and only if my_char_ptr is a null pointer, because only null pointers compare equal to other null pointers.
my_char_ptr == (void*)0 converts my_char_ptr to void*, and then compares that to the result of converting 0 to void* (which is a null pointer). The comparison is true if and only if my_char_ptr is a null pointer because when you convert a pointer to void* the result is a null pointer if and only if the source is a null pointer.
The issue of whether null pointers are represented with 0 bits or not is interesting but irrelevant to the analysis of the code.
The practical danger of thinking that NULL is a null pointer (rather than merely a null pointer constant) is that you might think that printf("%p", NULL) has defined behaviour, or that foo(NULL) will call the void* overload of foo rather than the int overload, and so on.
No, because they incidentially used the only case where it is guaranteed to work as example.
Otherwise, yes.
Although practially you probably won't ever see a difference, strictly speaking, the concern is correct.
The C++ standard requires (4.10) that:
A null pointer constant (which is either an integral constant expression that evaluates to 0, or a prvalue of type std::nullptr_t) converts to the null pointer of any type.
Two null pointers of the same type compare equal.
A prvalue of type pointer-to-cv-T can be converted to pointer-to-cv-void, and the null pointer value will be adjusted accordingly.
Pointers of derived classes can be converted to pointers of base classes, and the null pointer value will be adjusted accordingly.
This means, if you are pedantic about the wording, that the null pointers of void and char and foo_bar are not only not necessarily zero bit patterns, but also are not necessarily the same. Only null pointers of the same type are necessarily the same (and actually, not even that is true, it only says that they must compare equal, which isn't the same thing).
The fact that it explicitly says "The null pointer value is converted to the null pointer value of the
destination type" signifies that this is not only an absurd, theoretical contortion of the wording, but indeed intended as a legitimate feature of an implementation.
That is regardless of the fact that the same literal 0 will convert to the null pointer of each type.
Incidentially, in their example, they compared to void*, which will work due to the above conversion rule. Also, in practice, the null pointer for every type is a zero bit pattern on every architecture that you are likely to encounter in your life (though of course, that's not guaranteed).
First, I'm not sure that (charPtr == 0) != (charPtr == (void*)0) is allowed, even in C++. In both cases, you're
converting a null pointer constant (0) to a pointer, which
results in a null pointer. And all null pointers should compare
equal.
Second, while I don't know the context of the passage you cite,
you really don't have to worry about NULL being (void*)0:
user code cannot legally define NULL (at least not if it
includes any standard headers), and the C++ standard requires
NULL to be defined as a null pointer constant; i.e. an
constant integral expression evaluating to 0. (Note that
despite its name, a null pointer constant cannot have a pointer
type.) So it might be 0 (the more or less standard
definition, since the very beginnings of C), or possibly 0L,
or even (1-1), but not ((void*)0). (Of course, it might
also be something like __nullptr, a compiler built-in constant
which evaluates to integer 0, but triggers a warning if not
converted immediately into a null pointer.
Finally: there's no requirement that a null pointer have all
0 bits, and there certainly have been cases where this wasn't
the case. On the other hand, there is a requirement that
comparing a null pointer to a null pointer constant will
evaluate to true; it's up to the compiler to make it work. And
since NULL is required to be defined as a null pointer
constant, whether you use NULL or 0 is purely a question of
personal preference and convention.
EDIT:
Just to clarify a little: the critical point involves conversion
of a "null pointer constant", an integral constant expression
evaluating to 0. What can surprise people is:
int zero = 0; // NOT a constant expression.
void* p1 = reinterpret_cast<void*>( zero );
void* p2 = 0;
if ( p1 == p2 ) // NOT guaranteed!
The results of converting a non-constant expression which
evaluates to zero to a pointer is not guaranteed to be a null
pointer.

Null pointer in C++

When in C++ I declare a null pointer to be int* p=0, does that mean the zero is some special constant of integer pointer type, or does it mean that p is pointing to address 0x0?
Of course for that 0x0 would have to be an special address to which C++ never touches during allocation of variables/arrays.
The C++ standard defines that the integer constant 0 converts to a null pointer. This does not mean that null pointers point to address 0x0. It just means that the text '0' turns into a null pointer when converted to a pointer.
Of course, making null pointers have a representation other than 0x0 is rather complicated, so most compilers just let 0x0 be the null pointer address and make sure nothing is ever allocated at zero.
Note that using this zero-conversion is considered bad style. Use NULL (which is a preprocessor macro defined as 0, 0L, or some other zero integral constant), or, if your compiler is new enough to support it, nullptr.
It means that an integral constant expression with value zero has a special meaning in C++; it is called a null pointer constant. when you use such an expression to initialize a pointer with, or to assign to a pointer, the implementation ensures that the pointer contains the appropriately typed null pointer value. This is guaranteed to be a different value to any pointer pointing at a genuine object. It may or may not have a representation that is "zero".
ISO/IEC 14882:2011 4.10 [conv.ptr] / 1:
A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.
It's a special value, which by the standard is guaranteed to never be equal to a pointer that is pointing to an object or a function. The address-of operator & will never yield the null pointer, nor will any successful dynamic memory allocations. You should not think of it as address 0, but rather as special value that indicates that the pointer is pointing nowhere. There is a macro NULL for this purpose, and the new idiom is nullptr.
It means that it's not pointing to anything.
The value of the pointer is just 0. It doesn't necessarily mean it points to address 0x0. The NULL macro, is just a 0 constant.
the pointer points to address 0. On most platforms that is very special, but you should use NULL, because it is not always 0 (but very often).
Yes. Zero is a special constant. In fact, it's the only integral constant which can be used, without using explicit cast, in such statements:
int *pi = 0; //ok
char *pc = 0; //ok
void *pv = 0; //ok
A *pa = 0; //ok
All would compile fine.
However, if you use this instead:
int *pi = 1; //error
char *pc = 2; //error
void *pv = 3; //error
A *pa = 4; //error
All would give compilation error.
In C++11, you should use nullptr, instead of 0, when you mean null pointer.
In your example 'p' is the address of an int. By setting p to 0 you're saying there is an int at address 0. The convention is that 0 is the "not a valid address address", but its just a convention.
In pratice address 0 is generally "unmapped" (that is there is no memory backing that address), so you will get a fault at that address. That's not true in some embedded systems, though.
You could just as well pick any random address (e.g. 0xffff7777 or any other value) as the "null" address, but you would be bucking convention and confusing a lot of folks that read your code. Zero is generally used because most languages have support for testing is-zero is-not-zero efficiently.
See this related question: Why is address zero used for the null pointer?