0

After reading a lot of questions about null pointers, I still have confusion about memory allocation in null pointer.

If I type following code-

int a=22;
int *p=&a;//now p is pointing towards a
std::cout<<*p;//outputs 22
std::cout<<p;//outputs memory address of object a;
int *n=nullptr;// pointer n is initialized to null
std::cout<<n;

After compiling this code pointer n outputs literal constant 0, and if i try this,

std::cout<<*n;

this line of code is compiled by compiler but it is unable to execute, what is wrong in this code, it should print memory location of this pointer.

std::cout<<p;

does this output location of pointer in memory or location of an object in memory. Since many or all of these answers are already answered in previous questions but somehow i am unable to understand because I am beginner in C++.

7 Answers7

4

A nullptr pointer doesn't point to anything. It doesn't contain a valid address but a "non-address". It's conceptual, you shouldn't worry about the value it has.

The only thing that matters is that you can't dereference a nullptr pointer, because this will cause undefined behavior, and that's why your program fails at runtime (std::cout<<*n)

Jack
  • 131,802
  • 30
  • 241
  • 343
3
std::cout<<p;

In general outputs value of variable p, what that value means depends on p's type. In your case type or p is pointer to int (int *) so value of it is address of int. As pointer itself is an lvalue you can get address of it, so if you want to see where your pointer n located in memory just output it's address:

std::cout << &n << std::endl;

As said on many other answers do not dereference null pointer, as it leads to UB. So again:

std::cout << n << std::endl; // value of pointer n, ie address, in your case 0
std::cout << &n << std::endl; // address of pointer n, will be not 0 
std::cout << *n << std::endl; // undefined behavior, you try to dereference nullptr

If you want to see address of nullptr itself, you cannot - it is a constant, not lvalue, and does not have address:

std::cout << &nullptr << std::endl; // compile error, nullptr is not lvalue
Slava
  • 43,454
  • 1
  • 47
  • 90
2

nullptr is a special value, selected in such a way that no valid pointer could get this value. On many systems, the value is equal to numeric zero, but it is not a good idea to think of nullptr in terms of its numeric value.

To understand the meaning of nullptr you should first consider the meaning of a pointer: it is a variable that refers to something else, which may also refer to nothing at all. You need to be able to distinguish the state "my pointer refers to something" from the state "my pointer refers to nothing at all". This is where nullptr comes in: if a pointer is equal to nullptr, you know that it references "nothing at all".

Note: dereferencing nullptr (i.e. applying the unary asterisk operator to it) is undefined behavior. It may crash, or it may print some value, but it would be a "garbage value".

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

Dereferencing a null pointer is undefined behavior, so anything at all can happen. But, a null pointer still has to have a place in memory. So what you're seeing is just that. Typically compilers implement a null pointer as its value being all 0's.

Just because it's a gold quote, here's what Scott Meyer's has to say about UD behavior, from his book Effective C++ 2nd Ed.

"Nevertheless, there is something very troubling here. Your program's behavior is undefined -- you have no way of knowing what will happen... That means compilers may generate code to do whatever they like: reformat your disk, send suggestive email to your boss, fax source code to your competitors, whatever."

Community
  • 1
  • 1
jaredready
  • 2,398
  • 4
  • 23
  • 50
  • 1
    I'm not sure what you mean by "a null pointer still has to have a place in memory". All variables, including those of pointer type, are present somewhere in memory (unless they've been optimized out). But there typically is no memory at the address the nullptr points to; on machines with virtual memory, it will normally point to an unmapped address. – James Kanze Jul 15 '14 at 13:14
  • @JamesKanze "it will normally point to an unmapped address" I am afraid they have to always map it to 0, otherwise there will be a lot of compatibility issues. – Slava Jul 15 '14 at 13:25
  • I meant exactly what I said, as OP seemed to indicate he was confused that `std::cout << p` output something. I was just clarifying that a null pointer is a variable like any other, it just doesn't point to anything. – jaredready Jul 15 '14 at 13:25
  • @ResidentBiscuit "a null pointer is a variable like any other" this is confusing at least. A null pointer is a value for a pointer. Like 123 is a value for an int. The fact that this value have special meaning for pointers does not make it variable. – Slava Jul 15 '14 at 13:31
  • I think we're arguing semantics here. A pointer is a variable. A null pointer is a pointer with a special value. This does not change the fact a null pointer is a pointer which is a variable. `nullptr` is a value, a null pointer is a pointer with the value `nullptr`. – jaredready Jul 15 '14 at 13:35
  • @Slava: There is quite a bit of misconceptions here. There is no requirement that a pointer initialized with `nullptr` (or literal `0`) points to address 0. In particular in some systems you can get the OS to map address 0 to actual read/write memory and use it **but** using a `nullptr` to access that memory is still undefined behavior and the compiler can and will make use of that for optimizations, possibly removing code. That is, `void *ptr = mmap(0, 4096, prot, MAP_FIXED, fd, offset);`, if it succeeds, will map address 0, and `ptr` will point to it, but: `int *p = 0; *p = 10;` is still UB – David Rodríguez - dribeas Jul 15 '14 at 13:43
  • @Slava: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html for a description (from LLVM), or http://lwn.net/Articles/342330/ for an article in which the compiler (gcc in this case) optimizing based on `nullptr` (literal `0` in this case) removed code causing a security hole in linux. Similar optimization in Visual Studio is described here: http://blogs.msdn.com/b/oldnewthing/archive/2014/06/27/10537746.aspx – David Rodríguez - dribeas Jul 15 '14 at 13:47
  • @Slava On all of the machines I've worked on since we've had virtual memory, the null pointer would correspond to the address 0, and none of them map the address 0. Try it: dereference a null pointer, and you'll get a segment violation. (This wasn't the case in older days. Write through a null pointer, and you'd modify the OS.) – James Kanze Jul 15 '14 at 16:45
  • @DavidRodríguez-dribeas But would the `mmap` succeed. Would the system accept mapping something to the address 0? (I suspect that a lot of implementations have `MAP_FAILED` defined to be a null pointer, in which case, `mmap` at the address 0 will always fail.) – James Kanze Jul 15 '14 at 16:50
  • @JamesKanze you probably misunderstand me, I mean nullptr will always map to the address 0, though standard does not require that explicitly. Not that hardware will map address 0 to physical memory. – Slava Jul 15 '14 at 16:51
  • @James: see the link above (lwm.net) for an exploit that used that not too long ago. The `mmap` can be made to work on Linux. – David Rodríguez - dribeas Jul 15 '14 at 16:53
  • @Slava There's no rule that null pointer will always map to the address 0, and there have definitely been implementations where it didn't. (For that matter, there have been machines without linear addressing, where an address didn't "map" to an integer at all. At one time, in fact, they were widespread, and I learned C++ on one.) – James Kanze Jul 16 '14 at 10:12
2

When you compile:

std::cout << *n;

The compiler will typically build some code like this:

mov    rax, qword ptr [rbp - 0x40]
mov    esi, dword ptr [rax]
call cout

The first line looks up the address of the pointer (rdp - 0x40) and stores it in the CPU register RAX. In this case the address of the nullptr is 0. RAX now contains 0.

The second line tries to read memory from the location (0) specified by RAX. On a typical computer setup memory location 0 is protected (it isn't a valid data memory location). This causes an invalid operation and you get a crash*.

It never reaches the third line.

*However, this isn't necessary true in all circumstances: on a micro-controller where you don't have an operating system in place, this might successfully dereference and read the value of memory location 0. However *nullptr wouldn't be a good way of expressing this intention! See http://c-faq.com/null/machexamp.html for more discussion. If you want the full detail on nullptr: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf

JCx
  • 2,689
  • 22
  • 32
1

It is undefined behavior to dereference a null pointer. Any behavior that the compiler chooses or unintentionally happens is valid.

Changing the program in other places may also change the behavior of this code line.

selalerer
  • 3,766
  • 2
  • 23
  • 33
0

I suspect that your confusion revolves around the fact that there are two memory locations involved here.

In this code:

int *n=nullptr;// pointer n is initialized to null

There is one variable, n, and that variable occupies space in memory. You can take the address of n and prove this to yourself:

std::cout << &n << "\n";

And you'll see that the address-of n is something legitimate. As in, not NULL.

n happens to be of type pointer-to-int, and the thing it points to is NULL. That means it doesn't point to anything at all; it's in a state where you can't dereference it.

But "dereference it" is exactly what you are doing here:

std::cout<<*n;

n is valid, but the thing it points to is not. That is why your program is ill-formed.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • OK u meant that after derefrencing it onlt variable n of type int remains in memory and what about location of memory of nullptr ? –  Jul 16 '14 at 16:26