Search

6.7a — Null pointers

Null values and null pointers

Just like normal variables, pointers are not initialized when they are instantiated. Unless a value is assigned, a pointer will point to some garbage address by default.

Besides memory addresses, there is one additional value that a pointer can hold: a null value. A null value is a special value that means the pointer is not pointing at anything. A pointer holding a null value is called a null pointer.

In C++, we can assign a pointer a null value by initializing or assigning it the literal 0:

Pointers convert to boolean false if they are null, and boolean true if they are non-null. Therefore, we can use a conditional to test whether a pointer is null or not:

Best practice: Initialize your pointers to a null value if you’re not giving them another value.

Dereferencing null pointers

In the previous lesson, we noted that dereferencing a garbage pointer would lead to undefined results. Dereferencing a null pointer also results in undefined behavior. In most cases, it will crash your application.

Conceptually, this makes sense. Dereferencing a pointer means “go to the address the pointer is pointing at and access the value there”. A null pointer doesn’t have an address. So when you try to access the value at that address, what should it do?

The NULL macro

C (but not C++) defines a special preprocessor macro called NULL that is #defined as the value 0. Even though this is not technically part of C++, its usage is common enough that it should work in every C++ compiler:

However, because NULL is a preprocessor macro and because it’s technically not a part of C++, best practice in C++ is to avoid using it.

nullptr in C++11

Note that the value of 0 isn’t a pointer type, so assigning 0 to a pointer to denote that the pointer is a null pointer is a little inconsistent. In rare cases, when used as a literal argument, it can even cause problems because the compiler can’t tell whether we mean a null pointer or the integer 0:

To address these issues, C++11 introduces a new keyword called nullptr. nullptr is both a keyword and an rvalue constant, much like the boolean keywords true and false are.

Starting with C++11, this should be favored instead of 0 when we want a null pointer:

C++ will implicitly convert nullptr to any pointer type. So in the above example, nullptr is implicitly converted to an integer pointer, and then the value of nullptr assigned to ptr. This has the effect of making integer pointer ptr a null pointer.

This can also be used to call a function with a nullptr literal:

Best practice: With C++11, use nullptr to initialize your pointers to a null value.

std::nullptr_t in C++11

C++11 also introduces a new type called std::nullptr_t (in header <cstddef>). std::nullptr_t can only hold one value: nullptr! While this may seem kind of silly, it’s useful in one situation. If we want to write a function that accepts a nullptr argument, what type do we make the parameter? The answer is std::nullptr_t.

You probably won’t ever need to use this, but it’s good to know, just in case.

6.8 -- Pointers and arrays
Index
6.7 -- Introduction to pointers

35 comments to 6.7a — Null pointers

  • Peter Baum

    These sentences are confusing to me:

    "C++ will implicitly convert nullptr to any pointer type.  So in the above example, nullptr is implicitly converted to an integer pointer, and then the value of nullptr (0) assigned to ptr."

    1. It isn't clear to me exactly what "integer pointer" means.  Addresses, after all, are integer values.  Pointers have a context associated with them: they are integer values that are to be used as addresses.  Is an “integer pointer” just a pointer or is it a pointer without the address context and therefore just an integer?

    2. Writing nullptr{0} makes it look as though nullptr were a simple variable, hiding the issue of its other characteristics (a pointer but not a valid address value).

    3. We are told that nullptr can be converted to 0 implicitly.  After this conversion, we have to guess as to what we can do with that 0.  Can we use it exactly as we would use the literal 0?  If so, then nothing is gained over just using 0.  Apparently, some of this nullptr characteristic remains after the conversion to 0, but we are not told exactly what this means in practice.

    4. From the example, it appears that there is either an implicit conversion from nullptr to boolean when a boolean is needed, or there is an implicit conversion from 0 to boolean because any retained nullptr characteristics do not interfere with such conversion.  Clarification would be helpful.

    5. Perhaps the simplest solution to this issue is simply to state that there can be an implicit conversion of nullptr to false.

    • nascardriver

      1.

      This isn't about the way pointers are implemented but about the data type the pointer is pointing to.

      3/4/5. Quoting the C++ Standard Draft N4659
      "A value of type std::nullptr_t can be converted to an integral
      type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type." - § 8.2.10 4
      "For direct-initialization (11.6), a prvalue of type std::nullptr_t can
      be converted to a prvalue of type bool; the resulting value is false" - § 7.14 1
      I'd like to tell you more about the implementation of @nullptr and @std::nullptr_t, but I can't any. I assume @nullptr can be directly converted to an integral and bool type (std::nullptr_t -> bool, not std::nullptr_t -> int -> bool).
      I also assume that every remotely popular compiler doesn't do any conversions at run-time but rather replaces nullptr with a 0.

      • Peter Baum

        Hi nascardriver,

        If your interpretation of that section is correct about an integer pointer meaning the type the pointer is pointing to, then the section is even more confusing than I thought it was.  Maybe Alex can weigh in.  

        The rest of your comment makes sense to me except for the last part.  I have my doubts about compilers simply replacing the nullptr with 0 at run-time for two reasons.  Doing so would mean that the pointer could never access memory location 0.  Second, it would mean that if that location is protected memory, you would have to special case an address 0 access violation.  Of course, it is possible you are correct.  My assumption is that being a nullptr is identified as such in the structure that holds all the necessary information about a pointer.

        I also ran into an interesting situation where I didn't initialize a pointer to anything.  The program ran fine in debug mode but when I tried to run it in release mode, it was the linker that failed.  All this under Visual Studio.

        • nascardriver

          > I have my doubts about compilers simply replacing the nullptr with 0
          G++ does. You know assembly, get IDA and check out how VS handles nullptr.
          (nullptr is 0 with VS too, because Windows used NULL (aka. 0) before nullptr was introduced. NULL is still used in the Windows API)

          > Doing so would mean that the pointer could never access memory location 0.
          I'll change my sentence to -but rather replaces nullptr with a null pointer constant.-
          Since it's implementation specific what a null pointer constant is. Anything but 0 is ridiculous in my opinion.

          > you would have to special case an address 0 access violation
          Visual Studio has "Access violation reading location 0x00000000"
          Linux aborts with a Segmention Fault
          I don't know what Apple does, I assume it's similar.

          > I didn't initialize a pointer to anything.  The program ran fine in debug mode
          Ha! It could've continued running fine in release mode and one day it stops working when it's deployed on a customers system. That's why I initialize my variables. That pointer would've been a nullptr and the program wouldn't have worked in the first place.
          VS initializes uninitialized memory to 0xCC in debug mode. I don't know what the linker is doing here, it shouldn't care about values.

          References
          IDA Pro https://www.hex-rays.com/products/ida/support/download_freeware.shtml

          • Peter Baum

            Thanks nascardriver.  Helpful.

            I was wrong about the problem ultimately being a linker problem.  It was really a compiler problem that then led to a linker failure (why they would call the linker after such an error is an open question).

            By the way, there was nothing wrong at all with the program that didn't initialize the pointer to an array of structures.  It was always properly initialized prior to use.  The compiler just worried about it.  Still, I agree it is best to initialize in that instance.

            There are still things I don't understand though.  The following program fails to compile in either debug or release mode because the pointer is not initialized to nullptr:

            But this one is perfectly fine in either debug or release mode:

            (You can also put the pointer p inside the function and comment out the free(p) with the same result.)

            I have yet to find an example other than a large program that will produce an error only in release mode.  Maybe the smaller programs get the issue optimized out?

            • nascardriver

              Your first program compiles without error and warnings for me. It should compile for you to. C4701 and C4703 are warnings, not errors.

              > compiler never noticed this can't execute either
              I haven't yet encountered a C++ compiler that checks if code is reachable. I guess there are too few cases in which unreachable code can be detected without a major impact on compilation speed for such a feature to be added.

              Notes:
              * Use @std::malloc and @std::free from <cstdlib>. A lot of functions were moved to the @std namespace to avoid name collisions.
              * @malloc and @free aren't usually used in C++. I don't think there's anything wrong with them, but I'd go for @new and @delete.

              • Peter Baum

                No, they are errors with the way I have Visual Studio Community 2017 setup.  Two errors identified:

                Error    C4703    potentially uninitialized local pointer variable 'p' used    nullptrTest    

                Error    LNK1257    code generation failed    nullptrTest        1

                • nascardriver

                  They're still warnings, you're just treating them as errors, which is a good setup.
                  The warnings are justified, because @p might be uninitialized when it's used.
                  You can disable the warnings in question if you really want to by using

                  I can't test this, I don't have VS.
                  The proper solution would be to initialize @p.

                • Peter Baum

                  In VS you can right click on the program in the solution explorer and then click on properties, then C/C++ and that gets you to the choices of how you want to treat warnings.  

                  We are in agreement about initialization.

                  Thanks.

    • Alex

      I updated the lesson a little bit based on your feedback. New phrasing as follows: "C++ will implicitly convert nullptr to any pointer type. So in the above example, nullptr is implicitly converted to an integer pointer, and then the value of nullptr assigned to ptr. This has the effect of making integer pointer ptr a null pointer."

      I removed the note about nullptr typically being 0, because it doesn't really add anything to the discussion, and technically a null pointer constant doesn't have to be 0, though I'm not aware of any cases where 0 isn't used for that purpose. The memory address 0 is almost always reserved for null pointers and is generally treated as a protected address.

      Note that nullptr won't implicitly convert to integer value 0 (you can try this yourself and your compiler should complain). It will convert to an integer pointer (or any other pointer type) pointing to null (typically memory address 0).

      • Peter Baum

        Hi Alex,

        Helpful, but

        1. Based on the confusion nascardriver and I expressed, there is still the issue of what "integer pointer" means.  I assumed that "integer" was being applied to the value of the pointer, not the type of the object the pointer was pointing to.  Nascardriver had the opposite interpretation.  If he is correct, then the fact that the target type is integer is not really relevant to the fact that the 0 being discussed is also an integer.  Thus it would be less confusing to use an example where the type being pointed to was something other than an integer, say a double.

        2. I was more interested in the conversion to boolean, since examples were given that stuck the pointer in a logical expression.

        • Alex

          1) "integer pointer" is common shorthand for "pointer to an integer" (as the value of the pointer itself is always a memory address, which is integral by nature). I'll clarify this bit of nomenclature in the intro article on pointers (since I use the term "integer pointer" there too). That said, I agree with your assertion that it would be better to use a non integral pointer for this example. I'll update the article.

          2) A pointer converts to boolean false if the pointer is null and boolean true otherwise.

  • Matt

    So, based on what we know up to this point in the tutorials, if we want to call a function without any required parameters, is it still considered safe to just do:

    If so, I guess I'm not seeing any use for these things yet.  Reading some of the comments below it sounds like it will be clearer sometime in the future.

    /Matt

  • Bonez

    Is that ok?

    • nascardriver

      Hi Bonez!

      Uniform initializers (The ones with curly brackets) are good practice, use them whenever you can, they assure that you’re initializing a variable with a value of the right type.

      PS: Please edit your comments instead of deleting and re-posting them, the code will be highlighted correctly after refreshing the page.

    • Alex

      Yup, and I updated the lesson to use uniform initialization for all examples.

  • Joao Miguel Machado

    Hey, I have a question 🙂

    Could I use this type std::nullptr to overload a function?
    For example say I want to write a function to record audio from a microcontroller or something. And I turn the device on but record no data, which could be a nullptr. Then this function that I overload does something when gets the nullptr and the other overloaded function is called when I don't feed it with the nullptr.

    I don't see how this could be better than justa making a 'if', but could this be done?

    Thanks 😀

    • Alex

      Yes, like this:
      1) Overload a function using a pointer argument (of any type).
      2) Overload the same function with a std::nullptr_t argument.

      If you pass the function a valid pointer, it will match #1. If you pass in a null, #2 is a better match, so it should use that.

  • Astronoid

    Hello Alex,
    What is the difference between:

    and

    ; and what is the mean of the second one, and thanks.

    • Alex

      The first parameter is a pointer, so the argument is passed by address.
      The second parameter is a reference to a pointer. This means the doSomething() function can change the address held by the argument passed into Ptr.

  • Joao Gueifao

    I got confused on why C++11 would define something like nullptr_t in the first place...

    Suggestion: At the section "std::nullptr_t in C++11", why not motivating its usefulness in something like overloaded methods that take a pointer as argument, which is something to be explained at a later lesson?

    By the way, thank you so much for your tutorial, it simply rocks!

    Reference:
    https://stackoverflow.com/questions/12066721/what-are-the-uses-of-the-type-stdnullptr-t

    • Alex

      I don't discuss the motivations for std::nullptr_t here because I haven't talked about what an overloaded function is yet.

      But that's the primary case. Without std::nullptr_t, you can't disambiguate void somefcn(int) and void somefcn(*int) when calling somefcn(0). Is 0 an int or a null pointer?

  • alex be like

    number.number

    introduction blablablablablablablabla

    some codes

    prints
    bla

    blablablabla....
    .
    .
    .
    .
    .
    .
    some thousand lines, 1 hour and a headache later
    rule: you won't need those. *insert troll face here*

    I love your tutorials
    you are the best.. 🙂

    • Alex

      Haha. If you think these programs are long, wait until you get to the comprehensive quiz for this chapter! 😉

      • J3ANP3T3R

        Question : the use of assigning nullptr to a pointer is so that we can check later if it is not pointing to anything ? or are there any other use for it ?

        • Alex

          Yes, that's right. We use nullptr as a way to say, "this pointer isn't pointing to anything right now". That way, we can determine whether the pointer is pointing to something or not via a simple if statement.

          The other (related) use for nullptr is to pass a null value into a pointer function parameter.

          • Hussain

            Amazing lessons Alex, Thanks a million 😉

            I was told that one bad use of pointers is to make pointers that point to nothing (AKA, dangling pointers). From above, I have the feeling that I was misinformed in the past!

            Would you kindly give example on uses we want to pass null value into a pointer function parameter?

            Also, is it true that null as an argument isn't as ()?

            Thanks in advance =)

            • Alex

              Let's be careful what we mean by "nothing". Null pointers and dangling pointers are not the same thing.

              A null pointer points to "nothing" (address 0). That is okay, because "nothing" is an acceptable known value that we can test for and work around.
              A dangling pointer points to a valid memory address, but not one that has been allocated for your application's use. These are he pointers that will get you in trouble, because there's no way to distinguish a dangling pointer from a valid one.

              I added an academic example of passing a nullptr to a function in the lesson. While this isn't particularly useful, it does show the mechanics. As for useful examples, we'll see some of those when we get into classes and object-oriented programming (in particular, we use a special type of function called a constructor to initialize our classes -- if our class contains a pointer and we want to initialize it to a null value, we'd pass in a null value).

              > Also, is it true that null as an argument isn’t as ()?

              null (0 or nullptr) is an explicit literal value, whereas () is an empty argument. They are definitely not the same thing -- one is an argument, one is the lack of an argument.

  • Jim

    Alex,
    At the beginning of this lesson you introduced a null pointer, int *ptr(0); which was changed to int *ptr = nullptr
    by C++11. I still like the former!

    Was this done since int*prt(5) and int *prt = 5 are both improper syntax. Since you can not assign a literal to a pointer variable?

    • Alex

      It was done mainly to help disambiguate whether a literal 0 was intended as an integer or null pointer. If you like the old-style, it will certainly continue to be supported.

  • Typo in the second code example:

    in 4th line, "an double" should be "a double".

  • csvan

    I believe there is an error in the last example in the section "the null pointer" here: did you not mean to dereference the pointer inside the if-condition, in order to check wether or not it points to anything? Right now it is written without a dereference operator.

    Keep coding. Use it for good 🙂

    • baldo

      The if (pnPtr) test to see if the pointer is null. If it is a null pointer then the address it is pointing is 0 (false). If the pointer is allocated (not null) then pnPtr points to a address != 0 (which means true).

Leave a Comment

Put all code inside code tags: [code]your code here[/code]