What exactly is meant by "de-referencing a NULL pointer"? - c

I am a complete novice to C, and during my university work I've come across comments in code that often refer to de-referencing a NULL pointer. I do have a background in C#, I've been getting by that this might be similar to a "NullReferenceException" that you get in .Net, but now I am having serious doubts.
Can someone please explain to me in layman's terms exactly what this is and why it is bad?

A NULL pointer points to memory that doesn't exist. This may be address 0x00000000 or any other implementation-defined value (as long as it can never be a real address). Dereferencing it means trying to access whatever is pointed to by the pointer. The * operator is the dereferencing operator:
int a, b, c; // some integers
int *pi; // a pointer to an integer
a = 5;
pi = &a; // pi points to a
b = *pi; // b is now 5
pi = NULL;
c = *pi; // this is a NULL pointer dereference
This is exactly the same thing as a NullReferenceException in C#, except that pointers in C can point to any data object, even elements inside an array.

Dereferencing just means accessing the memory value at a given address. So when you have a pointer to something, to dereference the pointer means to read or write the data that the pointer points to.
In C, the unary * operator is the dereferencing operator. If x is a pointer, then *x is what x points to. The unary & operator is the address-of operator. If x is anything, then &x is the address at which x is stored in memory. The * and & operators are inverses of each other: if x is any data, and y is any pointer, then these equations are always true:
*(&x) == x
&(*y) == y
A null pointer is a pointer that does not point to any valid data (but it is not the only such pointer). The C standard says that it is undefined behavior to dereference a null pointer. This means that absolutely anything could happen: the program could crash, it could continue working silently, or it could erase your hard drive (although that's rather unlikely).
In most implementations, you will get a "segmentation fault" or "access violation" if you try to do so, which will almost always result in your program being terminated by the operating system. Here's one way a null pointer could be dereferenced:
int *x = NULL; // x is a null pointer
int y = *x; // CRASH: dereference x, trying to read it
*x = 0; // CRASH: dereference x, trying to write it
And yes, dereferencing a null pointer is pretty much exactly like a NullReferenceException in C# (or a NullPointerException in Java), except that the langauge standard is a little more helpful here. In C#, dereferencing a null reference has well-defined behavior: it always throws a NullReferenceException. There's no way that your program could continue working silently or erase your hard drive like in C (unless there's a bug in the language runtime, but again that's incredibly unlikely as well).

It means
myclass *p = NULL;
*p = ...; // illegal: dereferencing NULL pointer
... = *p; // illegal: dereferencing NULL pointer
p->meth(); // illegal: equivalent to (*p).meth(), which is dereferencing NULL pointer
myclass *p = /* some legal, non-NULL pointer */;
*p = ...; // Ok
... = *p; // Ok
p->meth(); // Ok, if myclass::meth() exists
basically, almost anything involving (*p) or implicitly involving (*p), e.g. p->... which is a shorthand for (*p). ...; except for pointer declaration.

From wiki
A null pointer has a reserved value, often but not necessarily the value zero, indicating that it refers to no object
..
Since a null-valued pointer does not refer to a meaningful object, an attempt to dereference a null pointer usually causes a run-time error.
int val =1;
int *p = NULL;
*p = val; // Whooosh!!!!

Quoting from wikipedia:
A pointer references a location in
memory, and obtaining the value at the
location a pointer refers to is known
as dereferencing the pointer.
Dereferencing is done by applying the unary * operator on the pointer.
int x = 5;
int * p; // pointer declaration
p = &x; // pointer assignment
*p = 7; // pointer dereferencing, example 1
int y = *p; // pointer dereferencing, example 2
"Dereferencing a NULL pointer" means performing *p when the p is NULL

A NULL pointer points to memory that doesn't exist, and will raise Segmentation fault. There's an easier way to de-reference a NULL pointer, take a look.
int main(int argc, char const *argv[])
{
*(int *)0 = 0; // Segmentation fault (core dumped)
return 0;
}
Since 0 is never a valid pointer value, a fault occurs.
SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL}

Lots of confusion and confused answers here. First of all, there is strictly speaking nothing called a "NULL pointer". There are null pointers, null pointer constants and the NULL macro.
Start by studying my answer from Codidact: What's the difference between null pointers and NULL? Quoting some parts of it here:
There are three different, related concepts that are easy to mix up:
null pointers
null pointer constants
the NULL macro
Formal definitions
The first two of these terms are formally defined in C17 6.3.2.3/3:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer
constant.67) 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.
In other words, a null pointer is a pointer of any type pointing at a
well-defined "nowhere". Any pointer can turn into a null pointer when
it is assigned a null pointer constant.
The standard mentions 0 and (void*)0 as two valid null pointer
constants, but note that it says "an integer constant expression with
the value 0". This means that things like 0u, 0x00 and other
variations are also null pointer constants. These are particular
special cases that can be assigned to any pointer type, regardless of
the various type compatibility rules that would normally apply.
Notably, both object pointers and function pointers can be null
pointers. Meaning that we must be able to assign null pointer
constants to them, no matter the actual pointer type.
NULL
The note 67) from above adds (not normative):
67) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
where 7.19 simply defines NULL as (normative):
NULL which expands to an implementation-defined null pointer constant;
In theory this could perhaps be something other than 0 and
(void*)0, but the implementation-defined part is more likely saying
that NULL can either be
#define NULL 0 or #define NULL (void*)0 or some other integer
constant expression with the value zero, depending on the C library
used. But all we need to know and care about is that NULL is a null
pointer constant.
NULL is also the preferred null pointer constant to use in C code,
because it is self-documenting and unambiguous (unlike 0). It should
only be used together with pointers and not for any other purpose.
Additionally, do not mix this up with "null termination of strings", which is an entirely separate topic. Null termination of strings is just a value zero, often referred to either as nul (one L) or '\0' (an octal escape sequence), just to separate it from null pointers and NULL.
Dereferencing
Having cleared that out, we cannot access what a null pointer points at, because it is as mentioned a well-defined "nowhere". The process of accessing what a pointer points at is known as dereferencing, and is done in C (and C++) through the unary * indirection operator. The C standard specifying how this operator works simply states (C17 6.5.3.3):
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined
Where an informative note adds:
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
And this would be where "segmentation faults" or "null pointer/reference exceptions" might be thrown. The reason for such is almost always an application bug such as these examples:
int* a = NULL; // create a null pointer by initializing with a null pointer constant
*a = 1; // null pointer is dereferenced, undefined behavior
int* b = 0; // create a null pointer by initializing with a null pointer constant
// not to be confused with similar looking dereferencing and assignment:
*b = 0; // null pointer is dereferenced, undefined behavior

Let's look at an example of dereferencing a NULL pointer, and talk about it.
Here is an example of dereferencing a NULL pointer, from this duplicate question here: uint32_t *ptr = NULL;:
int main (void)
{
uint32_t *ptr = NULL;
// `*ptr` dereferences the NULL ptr
*ptr = 0;
return 0;
}
Memory hasn't been allocated for the uint32_t, so calling *ptr, which "dereferences" the pointer, ptr, or otherwise said: accesses memory at an unallocated (NULL--usually 0, but implementation-defined) address, is illegal. It is "undefined behavior"--ie: a bug.
So, you should statically (preferred, where possible), or dynamically allocate space for a uint32_t and then only dereference a pointer which points to valid memory, as follows.
Here is how to statically allocate memory and use it with a pointer. Note even that the memory for the pointer itself is statically allocated in my example!:
// allocate enough memory for a 4-byte (32-bit) variable
uint32_t variable;
// allocate enough memory for a pointer, which is **usually** 2 bytes on an
// 8-bit microcontroller such as Arduino, or usually 4 bytes on a 32-bit
// architecture, or usually 8 bytes on a 64-bit Linux computer, for example
uint32_t* ptr;
// assign the address of `variable` to the pointer; you can now say that
// `ptr` "points to" the variable named `variable`; in literal terms, `ptr` now
// contains the numerical value of the address of the first byte of the
// variable `variable`
ptr = &variable;
// Store a number into the 4-byte variable named `variable`, via a pointer to it
*ptr = 1234;
// OR, same exact thing as just above: store a number into that 4-byte
// variable, but this time via the variable name, `variable`, directly
variable = 1234;
Note, dynamic allocation is fine too, but static memory allocation is safer, deterministic, faster, better for memory-constrained embedded systems, blah blah blah. The point is simply that you cannot legally dereference any pointer (meaning: put an asterisk "dereference operator" in front of it, like *ptr) which does not point to a chunk of allocated memory. I generally allocate memory statically by declaring a variable.

Related

How is zero 'overloaded' when assigning values to pointers in C

This question was inspired by this snipped from a C book I've been working through
Where is says:
int num;
int *pi=0; // Zero referes to the null pointer, NULL
pi = &num;
*pi = 0; // Zero refers to the integer zero
We are accustomed to overloaded operators, such as the asterisk used
to declare a pointer, to dereference a pointer, or to multiply. The
zero is also overloaded. We may find this discomforting because we are
not used to overloading operands.
So I did a bunch of investigating with the debugger and my answer is what the debugger showed me. It's undefined behavior, I get that, but I'm not writing a program I'm trying to figure something out. Whatever the case, the pointer is initialized to 1 every time I run it, I'm not depending on that in some calculation, it's what the debugger repeatedly shows.
This is all just one question really, but I had to write more or it wouldn't accept it.
Why does *p=0 have different effects at different times? How is 0 overloaded?
How can I tell if *p=0 is making p a null pointer or if it is assigning 0 to a variable that p is pointing to? And how does the compiler know to assign a null at the address of p rather than the address that p points too?
$ cat prac.c
#include <stdio.h>
int main()
{
int num;
int *p;
printf("0) %p is %d\n",p,*p);
*p=0; //Why is this......
printf("1) %p is %d\n",p,*p);
num=5;
p=&num;
printf("2) Now %p is %d\n",p,*p);
*p=0; //....different than this
printf("3) p is not null, %p : %d\n",p,*p);
return 0;
}
$ ./prac
0) 0x7ffeb36b5c30 is 1 //pointer is initialized to 1, not-null, definitely out-of-bounds though
1) 0x7ffeb36b5c30 is 0
2) Now 0x7ffeb36b5b3c is 5
3) p is not null, 0x7ffeb36b5b3c : 0
The concept you're asking about is null pointer constants.
The C standard defines a null pointer constant as
An integer constant expression with the value 0, or such an expression cast
to type void *
So the expression 0, which is of type int, is also a null pointer constant. (Note that a null pointer constant needn't be of pointer type.)
The standard further says that:
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.
Given:
int n;
int *p;
this:
p = 0;
implicitly converts the int expression 0 to a null pointer of type int*, while this:
n = 0;
or
*p = 0;
does not perform an implicit conversion, because the object being initialized is already of type int.
The rules for when implicit conversions are invoked are stated in the description of the assignment operator. The same rules apply to initialization, argument passing, and return statements. These rules explicitly state that a null pointer constant is converted to the target type.
See the N1570 draft of the C11 standard (large PDF).
Null pointer constants and null pointers: 6.3.2.3
Simple assignment: 6.15.6.1
I'm not familiar with the book or article you cite, but it failed spectacularly in helping you Understand and Use Pointers in C.
What is a Pointer?
A pointer is simply a normal variable that holds the address of something else as its value. In other words, a pointer points to the address where something else can be found. Where you normally think of a variable holding an immediate values, such as int a = 5;, a pointer would simply hold the address where 5 is stored in memory, e.g. int *b = &a;. It works the same way regardless what type of object the pointer points to. (a pointer, is just a pointer....)
How to Declare, Assign an Address to & Reference the Value Pointed to
Let's take your example and look at what each line does (ignoring your p & pi typos and using p only):
int num; /* declares an integer 'num' whose value is uninitialized */
int *p = 0; /* declares a pointer 'p' and ininializes the address
* to a the constant expression 0. (a Null Pointer Constant)
*/
See C11 Standard - Null Pointer Constant (p3) which is a constant expression with the value 0, or such an expression cast to type void * (e.g. (void *)0). Virtually all C compilers, and if fact the C-Standard provide NULL for this purpose. (see: C11 Standard - 7.19 Common definitions ) So you would generally see:
int *p = NULL; /* declare and initialize 'p' to the Null Pointer Constant */
Next the unary operator '&' is used to obtain the address of an object. Here:
p = &num; /* assigns the address of 'num' as the value of 'p', so
* 'p' holds the address of 'num' (e.g. 'p' points to the
* memory location where 'num' is stored).
*/
The unary '*' opertor is the dereference operator and provides a way to directly access the value located at the memory address held (pointed to) by a pointer, so:
*p = 0; /* sets the value at the address held by 'p' to zero */
Now lets look at your code and output:
int num;
int *p;
printf("0) %p is %d\n",p,*p);
What is the address held by p and what is the value of num?
You have attempted to access the value of an uninitialized pointer and an uninitialized integer. You have just invoked Undefined Behavior. The defined operation of your code is over and anything can happen, from appearing to behave normally or SegFault'ing. You cannot access uninitialized values.
*p=0;
printf("1) %p is %d\n",p,*p);
p is now initialized to the Null Pointer Constant, you cannot dereference a NULL pointer -- Undefined behavior again.
num=5;
p=&num;
printf("2) Now %p is %d\n",p,*p);
Hallelujah! num is now initialized to 5 and p now holds (points to) a valid memory address! (but unfortunately once you invoke Undefined Behavior, the game is over, and you may or may not get the correct output, but luckily you appear to.
*p=0;
printf("3) p is not null, %p : %d\n",p,*p);
What does p point to? (hint: num). What does the dereference operator do? (hint: allows you to access the value at the memory location held by a pointer). So what did *p = 0; do? (hint: you just set the value of num to 0, which is the value at the address held by p)
Let me know if you have further questions.

Initializing a pointer in c and explanation what does it mean to de-reference a NULL pointer [duplicate]

I am a complete novice to C, and during my university work I've come across comments in code that often refer to de-referencing a NULL pointer. I do have a background in C#, I've been getting by that this might be similar to a "NullReferenceException" that you get in .Net, but now I am having serious doubts.
Can someone please explain to me in layman's terms exactly what this is and why it is bad?
A NULL pointer points to memory that doesn't exist. This may be address 0x00000000 or any other implementation-defined value (as long as it can never be a real address). Dereferencing it means trying to access whatever is pointed to by the pointer. The * operator is the dereferencing operator:
int a, b, c; // some integers
int *pi; // a pointer to an integer
a = 5;
pi = &a; // pi points to a
b = *pi; // b is now 5
pi = NULL;
c = *pi; // this is a NULL pointer dereference
This is exactly the same thing as a NullReferenceException in C#, except that pointers in C can point to any data object, even elements inside an array.
Dereferencing just means accessing the memory value at a given address. So when you have a pointer to something, to dereference the pointer means to read or write the data that the pointer points to.
In C, the unary * operator is the dereferencing operator. If x is a pointer, then *x is what x points to. The unary & operator is the address-of operator. If x is anything, then &x is the address at which x is stored in memory. The * and & operators are inverses of each other: if x is any data, and y is any pointer, then these equations are always true:
*(&x) == x
&(*y) == y
A null pointer is a pointer that does not point to any valid data (but it is not the only such pointer). The C standard says that it is undefined behavior to dereference a null pointer. This means that absolutely anything could happen: the program could crash, it could continue working silently, or it could erase your hard drive (although that's rather unlikely).
In most implementations, you will get a "segmentation fault" or "access violation" if you try to do so, which will almost always result in your program being terminated by the operating system. Here's one way a null pointer could be dereferenced:
int *x = NULL; // x is a null pointer
int y = *x; // CRASH: dereference x, trying to read it
*x = 0; // CRASH: dereference x, trying to write it
And yes, dereferencing a null pointer is pretty much exactly like a NullReferenceException in C# (or a NullPointerException in Java), except that the langauge standard is a little more helpful here. In C#, dereferencing a null reference has well-defined behavior: it always throws a NullReferenceException. There's no way that your program could continue working silently or erase your hard drive like in C (unless there's a bug in the language runtime, but again that's incredibly unlikely as well).
It means
myclass *p = NULL;
*p = ...; // illegal: dereferencing NULL pointer
... = *p; // illegal: dereferencing NULL pointer
p->meth(); // illegal: equivalent to (*p).meth(), which is dereferencing NULL pointer
myclass *p = /* some legal, non-NULL pointer */;
*p = ...; // Ok
... = *p; // Ok
p->meth(); // Ok, if myclass::meth() exists
basically, almost anything involving (*p) or implicitly involving (*p), e.g. p->... which is a shorthand for (*p). ...; except for pointer declaration.
From wiki
A null pointer has a reserved value, often but not necessarily the value zero, indicating that it refers to no object
..
Since a null-valued pointer does not refer to a meaningful object, an attempt to dereference a null pointer usually causes a run-time error.
int val =1;
int *p = NULL;
*p = val; // Whooosh!!!!
Quoting from wikipedia:
A pointer references a location in
memory, and obtaining the value at the
location a pointer refers to is known
as dereferencing the pointer.
Dereferencing is done by applying the unary * operator on the pointer.
int x = 5;
int * p; // pointer declaration
p = &x; // pointer assignment
*p = 7; // pointer dereferencing, example 1
int y = *p; // pointer dereferencing, example 2
"Dereferencing a NULL pointer" means performing *p when the p is NULL
A NULL pointer points to memory that doesn't exist, and will raise Segmentation fault. There's an easier way to de-reference a NULL pointer, take a look.
int main(int argc, char const *argv[])
{
*(int *)0 = 0; // Segmentation fault (core dumped)
return 0;
}
Since 0 is never a valid pointer value, a fault occurs.
SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL}
Lots of confusion and confused answers here. First of all, there is strictly speaking nothing called a "NULL pointer". There are null pointers, null pointer constants and the NULL macro.
Start by studying my answer from Codidact: What's the difference between null pointers and NULL? Quoting some parts of it here:
There are three different, related concepts that are easy to mix up:
null pointers
null pointer constants
the NULL macro
Formal definitions
The first two of these terms are formally defined in C17 6.3.2.3/3:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer
constant.67) 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.
In other words, a null pointer is a pointer of any type pointing at a
well-defined "nowhere". Any pointer can turn into a null pointer when
it is assigned a null pointer constant.
The standard mentions 0 and (void*)0 as two valid null pointer
constants, but note that it says "an integer constant expression with
the value 0". This means that things like 0u, 0x00 and other
variations are also null pointer constants. These are particular
special cases that can be assigned to any pointer type, regardless of
the various type compatibility rules that would normally apply.
Notably, both object pointers and function pointers can be null
pointers. Meaning that we must be able to assign null pointer
constants to them, no matter the actual pointer type.
NULL
The note 67) from above adds (not normative):
67) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
where 7.19 simply defines NULL as (normative):
NULL which expands to an implementation-defined null pointer constant;
In theory this could perhaps be something other than 0 and
(void*)0, but the implementation-defined part is more likely saying
that NULL can either be
#define NULL 0 or #define NULL (void*)0 or some other integer
constant expression with the value zero, depending on the C library
used. But all we need to know and care about is that NULL is a null
pointer constant.
NULL is also the preferred null pointer constant to use in C code,
because it is self-documenting and unambiguous (unlike 0). It should
only be used together with pointers and not for any other purpose.
Additionally, do not mix this up with "null termination of strings", which is an entirely separate topic. Null termination of strings is just a value zero, often referred to either as nul (one L) or '\0' (an octal escape sequence), just to separate it from null pointers and NULL.
Dereferencing
Having cleared that out, we cannot access what a null pointer points at, because it is as mentioned a well-defined "nowhere". The process of accessing what a pointer points at is known as dereferencing, and is done in C (and C++) through the unary * indirection operator. The C standard specifying how this operator works simply states (C17 6.5.3.3):
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined
Where an informative note adds:
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
And this would be where "segmentation faults" or "null pointer/reference exceptions" might be thrown. The reason for such is almost always an application bug such as these examples:
int* a = NULL; // create a null pointer by initializing with a null pointer constant
*a = 1; // null pointer is dereferenced, undefined behavior
int* b = 0; // create a null pointer by initializing with a null pointer constant
// not to be confused with similar looking dereferencing and assignment:
*b = 0; // null pointer is dereferenced, undefined behavior
Let's look at an example of dereferencing a NULL pointer, and talk about it.
Here is an example of dereferencing a NULL pointer, from this duplicate question here: uint32_t *ptr = NULL;:
int main (void)
{
uint32_t *ptr = NULL;
// `*ptr` dereferences the NULL ptr
*ptr = 0;
return 0;
}
Memory hasn't been allocated for the uint32_t, so calling *ptr, which "dereferences" the pointer, ptr, or otherwise said: accesses memory at an unallocated (NULL--usually 0, but implementation-defined) address, is illegal. It is "undefined behavior"--ie: a bug.
So, you should statically (preferred, where possible), or dynamically allocate space for a uint32_t and then only dereference a pointer which points to valid memory, as follows.
Here is how to statically allocate memory and use it with a pointer. Note even that the memory for the pointer itself is statically allocated in my example!:
// allocate enough memory for a 4-byte (32-bit) variable
uint32_t variable;
// allocate enough memory for a pointer, which is **usually** 2 bytes on an
// 8-bit microcontroller such as Arduino, or usually 4 bytes on a 32-bit
// architecture, or usually 8 bytes on a 64-bit Linux computer, for example
uint32_t* ptr;
// assign the address of `variable` to the pointer; you can now say that
// `ptr` "points to" the variable named `variable`; in literal terms, `ptr` now
// contains the numerical value of the address of the first byte of the
// variable `variable`
ptr = &variable;
// Store a number into the 4-byte variable named `variable`, via a pointer to it
*ptr = 1234;
// OR, same exact thing as just above: store a number into that 4-byte
// variable, but this time via the variable name, `variable`, directly
variable = 1234;
Note, dynamic allocation is fine too, but static memory allocation is safer, deterministic, faster, better for memory-constrained embedded systems, blah blah blah. The point is simply that you cannot legally dereference any pointer (meaning: put an asterisk "dereference operator" in front of it, like *ptr) which does not point to a chunk of allocated memory. I generally allocate memory statically by declaring a variable.

In C, why initializing pointer to 0 doesn't give compile time error?

I was playing around with pointers, and I tried to initialize a pointer variable with a value and not a memory location.
If I am initializing a pointer with a non-zero value, and it is clearly giving me a compile time error.
int *p = 1;
main.c:14:14: error: initialization makes pointer from integer without a cast [-Werror=int-conversion]
int *p = 1;
^
However, if I initialize it as value 0, it doesn't give me a compile time error.
int *p = 0; //no compile time error but segmentation fault
Why is this so? Is there a valid memory address like 0? Normally, an address location is shown as 0xffffff or similar way. How is 0 interpreted into a memory location?
Thanks
From the C11 Standard (draft):
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. 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.
Usualy 0 represent a "no address" asNULL. When you use it that way you can check:
if (p) {
doSomthingWith(*p)
}
You are allowed to assign 0 to a pointer because NULL is typically defined as 0 cast to a void *. Any other integer value is a type mismatch.
While you can cast some other integer value to a pointer to assign it a value, it rarely makes sense to do so unless you're dealing with an embedded environment where specific memory locations have known uses.
You're getting a segfault not because you're printing the pointer but because you dereference the pointer and attempt to print what it points to. Because the pointer has a NULL value, dereferencing it causes undefined behavior. In this case, it results in a segfault.
To print the pointer, do the following:
printf("%p\n", (void *)p);
Why is this so? Is there a valid memory address like 0? Normally, an
address location is shown as 0xffffff or similar way. How is 0
interpreted into a memory location?
Generally, the address 0 is not accessible for most of the operating systems, because they reserve it for other tasks.
In C, the address 0 is interpreted as a NULL pointer and a NULL pointer is a pointer that is interpreted as a pointer that is not referencing a valid memory location accessible by the program.
So, if you are defining int* p = 0 or int* p = NULL the program written in C is assuming that the pointer is pointing to nothing (not a 0xffffff address).
A literal 0 in a pointer context represents a null pointer constant. A 1 is always just a 1 and therefore an int.

Specific Value to a NULL Pointer

I was referring to NULL Pointer in What's the difference between a null pointer and a void pointer?
According to the post reply by #AnT, "Formally, each specific pointer type (int *, char * etc.) has its own dedicated null-pointer value"
I wrote simple program. But the pointer value is not fixed for integer or character. It changes sometimes. So how can we conclude that NULL pointer to int has a fixed value? Also the value of pointer is never 0.
#include <stdio.h>
int main()
{
int a;
char *ptr; // Declaring a pointer without initializing it
int *ptrToInt;
if(ptr)
{
printf("Pointer is not NULL\n");
printf("Value of pointer = %x\n",ptr);
printf("Value of pointer = %x\n",ptrToInt);
}
else
{
printf("Pointer is NULL\n");
printf("Value of pointer = %x",ptr);
printf("Value of pointer = %x\n",ptrToInt);
}
return 0;
}
NULL is a value that means a pointer of any type is not valid, and void* is a type. In C or C++, the constant 0 can be assigned to a pointer of any type, and will set it to a null pointer of that type. The constant NULL might be declared as 0, ((void*)0), or something else on an unusual system.
A NULL pointer is a pointer, of any type, that’s been set to the invalid value NULL. You have to set it to this value yourself; simply leaving a pointer with no initializer means it might contain garbage. (There are technically a few exceptions, but always initialize your variables.)
A void* is a type that can store any other type of pointer (except a pointer to a function). It can’t be dereferenced, and you can’t index it like an array or do pointer arithmetic on it. It’s typically used as syntactic sugar to let you call a function such as memset(), which just treats the address you give it as an array of bytes to be filled, or assign p = malloc(…), without an explicit cast. In other words, when you just treat a pointer as an untyped block of memory that will be turned into some type of object later, but you don’t care which.
If you want to test the bit values of null pointers of different types, I suggest a cast to uintptr_t and the printf() format specifier in <inttypes.h>. On most but not all implementations, these will all be zero.

When you're dealing with C and other languages that have pointers, does initializing a pointer automatically set it to null?

Let's say you have defined a (global or local) pointer variable such as this:
void *this_is_a_pointer;
without giving it the value " = NULL; "
Would this automatically give you a NULL ptr (a pointer that points to NULL)?
* Also, what does it mean for a null pointer to point to NULL? Is that saying that it could point to literally anywhere? (basically, what really is the "address location of NULL"?)
(global or local)
This is actually what makes the difference.
In general, if you didn't initialize a variable, it's not initialized and reading from it is undefined behavior. But if the variable has static storage duration, then it's automatically initialized to zero (null for pointers).
// foo.cpp
void* this_is_null;
void whatever(void)
{
static int* and_so_is_this;
}
void not_whatever(void)
{
float* but_this_local_is_uninitialized;
}
Definitely do not count on this. Compilers in Debug mode (with the correct switch settings) will typically zero variables on the stack for you to track down bugs, but it is better to explicitly initialize all of your variables not just pointers.
EDIT: In response to your edit, the value of NULL is defined as zero. So, it would point to address 0, which in most modern operating systems would result in a segmentation fault, or memory access violation. But, on some embedded operating systems with little memory management it would let you change the contents of address 0! This one has bit me a few times ;)
C Tutorial – More on Pointers
Initialise a pointer
Before you can use a pointer in for instance a printf statement, you
have to initialize the pointer. The following example will not
initialize the pointer:
#include<stdio.h>
void main()
{
int *ptr_p;
printf("%d\n",*ptr_p);
}
Note: We used void when we declared the function main(). So no return
0; is needed. (Some compilers will give a warning when void is used on
main(). GNU compiler will give the warning: return type of ‘main’ is
not ‘int’).
In this example we print the value that ptr_p points to. However, we
did not initialize the pointer. In this case the pointer contains a
random address or 0.
The result of this program is a segmentation fault, some other
run-time error or the random address is printed. The meaning of a
segmentation fault is that you have used a pointer that points to an
invalid address.
10.4 Null Pointers
The most straightforward way to ``get'' a null pointer in your program
is by using the predefined constant NULL, which is defined for you by
several standard header files, including , , and
. To initialize a pointer to a null pointer, you might use
code like
#include
int *ip = NULL;
< and to test it for a null pointer before inspecting
the value pointed to you might use code like
if(ip != NULL)
printf("%d\n", *ip);
It is also possible to refer to the null
pointer by using a constant 0, and you will see some code that sets
null pointers by simply doing
int *ip = 0;
(In fact, NULL is a preprocessor macro which typically
has the value, or replacement text, 0.) Furthermore, since the
definition of ``true'' in C is a value that is not equal to 0, you
will see code that tests for non-null pointers with abbreviated code
like
if(ip) printf("%d\n", *ip);
This has the same meaning as our
previous example; if(ip) is equivalent to if(ip != 0) and to if(ip !=
NULL). All of these uses are legal, and although I recommend that you
use the constant NULL for clarity, you will come across the other
forms, so you should be able to recognize them.
A pointer with static storage duration will be automatically initialized to NULL. A pointer with auto duration will not be initialized, and will contain a random value that may or may not correspond to a valid memory address:
#include <stdio.h>
int *p0; // File scope, initialized to NULL
int main(void)
{
static int *p1; // Declared "static", initialized to NULL
int *p2; // Auto, not initialized
printf("p0 = %p, p1 = %p, p2 = %p\n", (void *) p0, (void *) p1, (void *) p2);
return 0;
}
There is the null pointer constant, which is 0 (the macro NULL expands to a 0-valued pointer expression). There is the null pointer value, which may or may not be 0-valued; it's the value used by the underlying system to indicate a well-defined "nowhere". When a null pointer constant appears in your code, it will be replaced with the null pointer value.
A null pointer value is guaranteed to compare unequal to any valid pointer value.

Resources