Search

6.7 — Introduction to pointers

In lesson 1.3 -- a first look at variables, we noted that a variable is a name for a piece of memory that holds a value. When our program instantiates a variable, a free memory address is automatically assigned to the variable, and any value we assign to the variable is stored in this memory address.

For example:

When this statement is executed by the CPU, a piece of memory from RAM will be set aside. For the sake of example, let’s say that the variable x is assigned memory location 140. Whenever the program sees the variable x in an expression or statement, it knows that it should look in memory location 140 to get the value.

The nice thing about variables is that we don’t need to worry about what specific memory address is assigned. We just refer to the variable by its given identifier, and the compiler translates this name into the appropriately assigned memory address.

However, this approach has some limitations, which we’ll discuss in this and future lessons.

The address-of operator (&)

The address-of operator (&) allows us to see what memory address is assigned to a variable. This is pretty straightforward:

On the author’s machine, the above program printed:

5
0027FEA0

Note: Although the address-of operator looks just like the bitwise-and operator, you can distinguish them because the address-of operator is unary, whereas the bitwise-and operator is binary.

The dereference operator (*)

Getting the address of a variable isn’t very useful by itself.

The dereference operator (*) allows us to get the value at a particular address:

On the author’s machine, the above program printed:

5
0027FEA0
5

Note: Although the dereference operator looks just like the multiplication operator, you can distinguish them because the dereference operator is unary, whereas the multiplication operator is binary.

Pointers

With the address-of operator and dereference operators now added to our toolkits, we can now talk about pointers. A pointer is a variable that holds a memory address as its value.

Pointers are typically seen as one of the most confusing parts of the C++ language, but they’re surprisingly simple when explained properly.

Declaring a pointer

Pointer variables are declared just like normal variables, only with an asterisk between the data type and the variable name:

Note that the asterisk here is not a dereference. It is part of the pointer declaration syntax.

Syntactically, C++ will accept the asterisk next to the data type, next to the variable name, or even in the middle.

However, when declaring multiple pointer variables, the asterisk has to be included with each variable. It’s easy to forget to do this if you get used to attaching the asterisk to the type instead of the variable name!

For this reason, when declaring a variable, we recommend putting the asterisk next to the variable name.

Best practice: When declaring a pointer variable, put the asterisk next to the variable name.

However, when returning a pointer from a function, it’s clearer to put the asterisk next to the return type:

This makes it clear that the function is returning a value of type int* and not an int.

Best practice: When declaring a function, put the asterisk of a pointer return value next to the type.

Just like normal variables, pointers are not initialized when declared. If not initialized with a value, they will contain garbage.

Assigning a value to a pointer

Since pointers only hold addresses, when we assign a value to a pointer, that value has to be an address. One of the most common things to do with pointers is have them hold the address of a different variable.

To get the address of a variable, we use the address-of operator:

Conceptually, you can think of the above snippet like this:

This is where pointers get their name from -- ptr is holding the address of variable value, so we say that ptr is “pointing to” value.

It is also easy to see using code:

On the author’s machine, this printed:

0012FF7C
0012FF7C

The type of the pointer has to match the type of the variable being pointed to:

Note that the following is also not legal:

This is because pointers can only hold addresses, and the integer literal 5 does not have a memory address. If you try this, the compiler will tell you it cannot convert an integer to an integer pointer.

C++ will also not allow you to directly assign literal memory addresses to a pointer:

The address-of operator returns a pointer

It’s worth noting that the address-of operator (&) doesn’t return the address of its operand as a literal. Instead, it returns a pointer containing the address of the operand, whose type is derived from the argument (e.g. taking the address of an int will return the address in an int pointer).

We can see this in the following example:

On Visual Studio 2013, this printed:

int *

(With gcc, this prints “pi” (pointer to integer) instead).

This pointer can then be printed or assigned as desired.

Dereferencing pointers

Once we have a pointer variable pointing at something, the other common thing to do with it is dereference the pointer to get the value of what it’s pointing at. A dereferenced pointer evaluates to the contents of the address it is pointing to.

The above program prints:

0012FF7C
5
0012FF7C
5

This is why pointers must have a type. Without a type, a pointer wouldn’t know how to interpret the contents it was pointing to when it was dereferenced. It’s also why the type of the pointer and the variable address it’s being assigned to must match. If they did not, when the pointer was dereferenced, it would misinterpret the bits as a different type.

Once assigned, a pointer value can be reassigned to another value:

When the address of variable value is assigned to ptr, the following are true:

  • ptr is the same as &value
  • *ptr is treated the same as value

Because *ptr is treated the same as value, you can assign values to it just as if it were variable value! The following program prints 7:

A warning about dereferencing invalid pointers

Pointers in C++ are inherently unsafe, and improper pointer usage is one of the best ways to crash your application.

When a pointer is dereferenced, the application attempts to go to the memory location that is stored in the pointer and retrieve the contents of memory. For security reasons, modern operating systems sandbox applications to prevent them from improperly interacting with other applications, and to protect the stability of the operating system itself. If an application tries to access a memory location not allocated to it by the operating system, the operating system may shut down the application.

The following program illustrates this, and will probably crash when you run it (go ahead, try it, you won’t harm your machine):

The size of pointers

The size of a pointer is dependent upon the architecture the executable is compiled for -- a 32-bit executable uses 32-bit memory addresses -- consequently, a pointer on a 32-bit machine is 32 bits (4 bytes). With a 64-bit executable, a pointer would be 64 bits (8 bytes). Note that this is true regardless of what is being pointed to:

As you can see, the size of the pointer is always the same. This is because a pointer is just a memory address, and the number of bits needed to access a memory address on a given machine is always constant.

What good are pointers?

At this point, pointers may seem a little silly, academic, or obtuse. Why use a pointer if we can just use the original variable?

It turns out that pointers are useful in many different cases:

1) Arrays are implemented using pointers. Pointers can be used to iterate through an array (as an alternative to array indices) (covered in lesson 6.8).
2) They are the only way you can dynamically allocate memory in C++ (covered in lesson 6.9). This is by far the most common use case for pointers.
3) They can be used to pass a large amount of data to a function in a way that doesn’t involve copying the data, which is inefficient (covered in lesson 7.4)
4) They can be used to pass a function as a parameter to another function (covered in lesson 7.8).
5) They can be used to achieve polymorphism when dealing with inheritance (covered in lesson 12.1).
6) They can be used to have one struct/class point at another struct/class, to form a chain. This is useful in some more advanced data structures, such as linked lists and trees.

Don’t worry if you don’t understand what most of these are yet. Now that you understand what pointers are, we can start taking an in-depth look at the various cases in which they’re useful, which we’ll do in subsequent lessons.

Conclusion

Pointers are variables that hold a memory address. They can be dereferenced using the dereference operator (*) to retrieve the value at the address they are holding. Dereferencing a garbage pointer may crash your application.

Best practice: When declaring a pointer variable, put the asterisk next to the variable name.
Best practice: When declaring a function, put the asterisk of a pointer return value next to the type.

Quiz

1) What values does this program print? Assume a short is 2 bytes, and a 32-bit machine.

Quiz solutions

1) Show Solution

6.7a -- Null pointers
Index
6.6 -- C-style strings

72 comments to 6.7 — Introduction to pointers

  • Skylark

    *gets headache*

    Well, that was almost fun to read!

    What exactly is the POINT of a pointer? So far I’m just thinking of pointers as duplicates of other variables with similar functionality.

    You can determine the address of a value a pointer is ‘pointing’ to, but can’t you just use the ‘&’ operator to do that anyway?

    I don’t understand whyyyy! T^T

    • Setting a pointer to point at local non-array variable is an easy way to introduce pointers, but it’s not done all that often in practice.

      Pointers are used for a lot of things:
      1) They are the only way you can dynamically allocate memory in C++. This is by far their most common use. This topic is covered in lesson 6.9.
      2) You can use them to step through the values in an array (as an alternative to array indices).
      3) You can use them to pass a large struct/class to a function in a way that doesn’t involve copying the entire struct/class, which is inefficient (covered in lesson 7.4)
      4) You can use them to pass a function as a parameter to another function (covered in lesson 7.8).
      5) You can use them to achieve polymorphism when dealing with inheritance (covered in lesson 12.1).

      All of these things are covered in future lessons, but you’ve got to start somewhere. And this is where. 🙂

    • DanL

      Imagine you want to send an array with ten-thousand elements to a function.  If you send the whole array, memory has to be allocated and all of the elements copied.  If you send the pointer to the function instead, the function just gets the address of the array, not a new copy of the whole damn thing.  If the function makes changes to the array, they are global (kind of), not just changes to a copy.  It’s a way for disparate portions of a program to work on big bodies of data without needing a ton of global variables and a bunch of copies of the data.

  • Sakthi Sai Saranyan

    Very good tutorial. At last I could understand Pointers. 🙂

  • Darren Fuller

    Thank you, for the first time I’ve read something about pointers and it all makes sense and surprisingly easy going compared to other texts I’ve read.

  • chkwa

    if pointer holds the address of a variable, what if i want to know the pointer’s address it self how can i do that?

    • You can use the & operator to get the address of any variable (even a pointer).

      eg.
      int nX = 3; // nX has address 0x0012ff60. nX has value 3.
      int *pnX = &nX; // pnX has address 0012ff54. pnX has value 0x0012ff60
      cout << pnX; // prints value of pnX, which is 0x0012ff60 cout << &pnX; // prints address of pnX which is 0x0012ff54

  • This is a wonderful tutorial - the examples here clearly step through all possible pointer/pointed-to configurations. Thanks so much!

  • SWEngineer

    Simple well explained tutorial.

    Thanks a lot.

  • capitanui

    I have a question …i cannot understand something.
    I have this simple code :

    int *pValue;
    *pValue = 4;
    cout<<*pValue;

    It's all ok..it prints 4;

    I i declare another one my program crushes and i cannot understand why since is the same thing.

    int *pValue, *nValue;

    *pValue = 4;
    *nValue = 5;

    cout<<*pValue<<*nValue;

  • Ollie999

    on my computer (windows 7 64-bit) sizeof(pntr) returns 4 when I was expecting it to return 8 based on this tutorial. Does anyone know why this is?

    • Ollie999

      Also my computer has 8gb of ram so if pointers are only 32-bit for some reason then surely only half the computers memory could be used? I don’t get it.

      • Alex

        Even though your computer and OS are 64-bit, you’ve defined your project as creating a win32 (32-bit) application. This means your pointers will be 32-bits, and you’ll only be able to address up to 4GB of memory.

        If you changed your project settings to compile as a 64-bit application, you’d see your pointers become 8 bytes in size.

  • KILLDOZER

    Hey, Alex. I just wanted to let you know I really appreciate you not only giving away all this knowledge without asking in return, but doing so in such a well structured way. In my book, this makes you an admirable person. On a sideline, with the knowledge I’ve acquired thus far, I started making a text-based dungeon crawler. I’ve already made functions which can generate a random map, and draw it using X’s & whitespaces. I’m confident that it will turn out fairly nicely, and it’s all thanks to you.

  • alexlydiate

    This is a beautifully clear explanation - many thanks.

  • Joseph

    For being simple, clear, well-explained and easy to understand, I still don’t get pointers.
    I get that they have purpose and are extremely useful in large applications, I just can’t wrap my head around the way they’re used.
    Just seeing a pointer makes me super confused and a little angry that I can’t understand them as easily as everyone else does.

    I’ll try going through this section a few more times to see if it helps.

  • Julie

    I think I got it. hope its application will be easy 😀

  • Robot Cat

    Hello,
    Can you tell me What different between :
    - Pointer to a deallocation memory
    - Null Poiter (Pointer assign = 0)
    - And Pointer undefined (declaration without assignment)
    Or they are similar ?

    • Alex

      By “pointer to a deallocation memory” I presume you mean a pointer that is pointing to memory that has been deleted. These pointers will have a valid memory address, but the memory they are pointed to is no longer allocated for the application’s use.

      In the second case, the pointer is set to null. This is a way of indicating that the pointer is not pointing at anything.

      In the third case, an uninitialized pointer hold a garbage address from whatever was in memory beforehand. If you’re lucky, this will end up being zero’d out bits, so the pointer will be treated as a null pointer. If you’re unlucky, this will be to some random memory address not allocated for your program’s use.

      Dereferencing any of these pointers will lead to undefined behavior -- likely an application crash.

  • Todd

    Typo.

    "In other words, when pnPtr is assigned to &nValue:"

    I think you mean:

    "In other words, when &nValue is assigned to pnPtr:"

  • Shivam Tripathi

    I have a confusion in Pointers declaration….Is an asterisk (*) important to place before a pointer variable or any simple variable which when assigned an address of another variable can also become a pointer…i mean to say that consider this:

    But suppose i write lyk this:

    I ran this sample in my Dev-C++ compiler and got the expected O/P…it states that “invalid conversion from int* to int”…I understand this but why this conversion doesn’t happen..infact memory address is actually a number only…Even i tried with “double” in order to increase the storing range

    And Alex…plz respond to my question being asked in section 6.3 (Arrays & Loops)…seek ur advice…plz..:-)

    • Alex

      I think you answered your own question. Yes, you need the asterisk to denote that the variable is a pointer. If you don’t have it, C++ will complain about an invalid type conversion. The whole point of a strongly typed language (like C++ is) is to make sure you don’t inadvertently make conversions that don’t make sense, such as assigning a memory address to an integer rather than an integer pointer.

  • liyuan

    Hi Alex,

    I’m wondering why you name your variables with a small n in front, such as in "nValue". I think it’s (or i read it as) (integer)(Value) but I’m not 100% sure since you name short variables as nValue too.

    • Alex

      Ignore the prefixes. I used to recommend a certain prefix-based naming convention, but best practice has moved away from such, so I’m in the process of removing all the prefixes as I rewrite the lessons.

  • Joe

    Ok, this is killing me… what is this line?

    void foo(int *&p)
    {
    }

    foo takes as input a dereferenced address of p???

    Also, this site is amazing, thank you!

    • Alex

      In this case, p is a reference to the integer pointer argument. We haven’t covered references yet. But the short of it is that references can modify the argument values passed in. So when we call foo(p), the value of p may be changed by foo(). The compiler doesn’t know at compile-time whether foo() will assign a valid value to p or not, so it allows us to bypass the error we’d otherwise get about trying to reference an uninitialized value.

  • Manoj Kumar

  • Jim

    Alex,
    You should mention that all pointers are stored in the stack.

    Under Assigning a value to a pointer:

    You wrote "One of the most common things to do with pointers is have them hold the address of another variable."

    Don’t you mean a variable, not another variable? Another make this sound like there are two variables being pointer at.

    • Alex

      Pointers aren’t necessarily stored on the stack. It’s possible to dynamically allocate pointers. When that happens, the dynamically allocated pointers get allocated on the heap.

      I used the word “another” to mean a different variable, rather than the address of itself (having a pointer hold its own address isn’t very useful). I’ve updated the word “another” to “a different”.

  • Jim

    Alex,

    I mistook what you wrote below to be related to the code above it. May I suggest that you add the word "below" after "Note". So others don’t make the same mistake that I did.

    "Note that when the address of variable value is assigned to ptr:
    •ptr is the same as &value
    •*ptr is treated the same as value"

  • Rob G.

    In my humble opinion much of the struggle with pointers initially is dealing with confusion generated by the same items serving separate purposes. For example
    in the following code *nptr seems to be a single item just like a variable. Yet it has different purposes depending on context:

    Alex has done a really good job with this introduction. Thanks Alex!

  • DanL

    In the section "The address-of operator returns a pointer," if you read it one way, you imply that &x returns A POINTER to the address of x (or a pointer to a pointer to x), rather than the address of x.  I suggest re-wording it a bit. For clarification: &x evaluates to a hexadecimal address of x, and a pointer getting that value would be a pointer to x. Variables do not have unique pointers. There can be multiple pointers to x.

    • Alex

      &x does not evaluate to the address of x, it evaluates to a pointer that holds the address of x. That pointer can be evaluated to get the address of x. It is done this way because the pointer contains type information, whereas an address literal would not.

  • Shiva

    Typo: in the Declaring a pointer example, you wrote:

    Another thing: in more than one example you mixed up assignment with initialisation. I mean:

    should technically be:

    Or, to specifically show assignment (as in the topic ‘Assigning a value to a pointer’), wouldn’t it be better to write:

    Suggestion: it’d be good if you could include a note on how the & operator can be used to get the address of even a pointer variable itself in the lesson. Got it from your answer to reader chkwa’s question above. I don’t know how useful this is practically, but it clarifies a good deal about the concept.

    Nice quiz! Sums up everything taught in this lesson perfectly. And no matter how much I tried, the invalid pointer example runs fine on my system without crashing. Duh.

    • Alex

      No, a pointer doesn’t have to point to a named variable, it can point to a memory address that contains a value.

      Fixed the assignment vs initialization comment error. Thanks!

      Taking the address of a pointer variable is pretty uncommon. Although you can do it, in most cases you won’t have a reason to.

      • Shiva

        I didn’t know that about pointers. Thanks! 🙂

        If I did take the address of say an int pointer, and store it in another int pointer, what is the latter’s type info? Is it int **, or int * itself?

        • Alex

          int **. This is called a pointer to a pointer. I talk more about these in lesson 6.14.

        • Elpidius

          The latter’s type info is int **, however when declaring a pointer of type int **, make sure to declare a pointer of that type.

          Otherwise the compiler will give you an error: ‘cannot convert from ‘int **’ to ‘int *’.

  • Jim

    Alex,
    When and how do you destroy a pointer?  Are pointers global or local?   Normal variables are destroyed at the close of any body or function, are pointers destroyed then too?

    • Alex

      Pointers are just like normal variables, except inside of holding a value, they hold an address. Just like normal variables, they can be local or global, and if they are local, they get created and destroyed just like local non-pointer variables.

  • P

    Thank you for the tutorials!
    In one of the examples

    needs to  be replaced with

  • Jim

    Alex,
    There is a error in this lesson in this program it needs to read:

    I’m running it on Codeblocks 16.01 and it outputs Pi (This probably means its a Pointer to an Integer)Do other IDE print out the same way?

    • Alex

      I updated the example and made a note about pi. What compilers print for typeid().name() is up to the compiler. It’s not defined by the C++ standard, so each compiler is free to do whatever it wants. It’s useful for debugging, but I wouldn’t rely on it for anything else.

  • J3ANP3T3R

    Can you get the value of a memory address and store it in a variable ? if so, does data type matter ?      for example i have a given memory address and i wanted to get the value from this address and store it in a variable but before i can declare my variable how do i know what data type to use ? or is it always an integer value ?

    ok so i just read further on and find that it has to match. but i’m thinking of something like cheat engine etc. can i scan through a given set of memory address ( possible multiple data types ) and how do i store them on a temporary variable to check which data type they are ?

    • Alex

      Memory is just memory, it doesn’t contain any information about how to interpret the value it contains. That’s what variable types are for -- they provide a key for the program to know how to convert the bits in memory into the value we expect.

      You can get the value of a memory address -- this is essentially what using a variable is -- but in this context, dereferencing a pointer is probably a better example. The type of the pointer is used to interpret the value.

      If you were scanning the memory of another program, you’d have to guess or have some other information about how things were stored in memory to make sense of the values.

      • J3ANP3T3R

        i see.. im searching for a way to test scan a memory address or a set of memory addresses with an unknown data type. base on your reply i understand that memory does not hold any information as to what data type they hold just binary numbers.

        base on the examples above however ;

        iPtr = &dValue; // wrong -- int pointer cannot point to the address of a double variable

        since the compiler can tell if the data type of the pointer and the value do not match then maybe there is a way i could have the program try again with another data type then another and so on until the compiler is no longer showing me an error at run time ? possibly using some sort of error handler so the program wont terminate upon getting the error ?

        by the way if the value in a memory address is say myInt a char "4" is that the same as the integer 4 ? or do they both have different binary values ? if i declare a pointer say int *iPtr = &myInt and the compiler sees the value of &myInt is a character 4 is the compiler going to accept that ?

        • Alex

          If you’re scanning memory, that’s something you’d be doing at runtime, so the compiler would be unable to assist.

          Because chars are a type of integer, they are stored the same was as an integer (but have a different size). Because the size is different, the compiler won’t let you mix pointers between them (otherwise your int pointer would try to read 4 bytes, of which 1 byte was the original char, and 3 bytes are garbage).

  • Nyap

    is this the difference between 32-bit and 64-bit? 64-bit memory addresses are twice the size, which is why 64bit cpus can support a lot more memory?

    • Alex

      Yes! With 32 bits, you can only generate 4GB worth of unique memory addresses, which is why 32-bit operating systems are limited to that amount of memory.

  • Mr Alex,
    I’m just beginner in c++ and have following question: when variable’s value is 2 or more bytes, does pointer return the address of first byte?

    • Alex

      Yes. But that’s okay.

      When you dereference a pointer, the pointer’s type tells the compiler how many bytes to return as a value. So for example, an integer pointer may point to address 0xb000000, but if you dereference that pointer, it will return bytes 0xb0000000 through 0xb0000003 as an integer (assuming 4 byte integers).

      • Mr Alex, bon jour,
        Please let me express you my thanks for your immediate reply. I understand that address returning by pointer is the address of variable’s first byte.
        I run program with int x = 5 and address was 0x7ffff63109ec. Then I run it with int y = 5 and address was 0x7ffff72cea5c that is far from first. When I run it again with int y = 5 address was same, 0x7ffff72cea5c. But with int y = 6 address was 0x7fff860c155c also far. With long int y = 123456789 address was 0x7fffcabae0d8, and with long int x = 123456789 (same number) address was 0x7fff9ad7f998.
        Regards

        • Alex

          The address of a variable and the value it holds are distinct (have no relationship). The addresses may also change with each execution of the program, depending on where the operating system decides to load the program into memory.

  • Mr Alex,
    Please accept my thanks for your immediate reply and my sorrow for delay in my reply. I’m homeless in France forced to travel from town to town and get internet access for free in public libraries (médiathèques).
    So far I have learn from you that address pointed by pointer is the first byte’s of variable’s value. I hope learn from you many more.
    Regards

  • Mr Alex,
    Please permit me one more comment about address of variable’s value. When I posted massage by June 11, I was using Ubuntu. Now I use Windows and address changes when I run program again, and indeed when change variable’s type or name or value. Also new address is 4 bytes different than previous when type is "int" as you posted by June 10. So you are right on that it depends on the platform used. I have learned also this from you. Many thanks. I have to learn many from you about c++. Regards.

  • Prajwal

    Hey Alex,
    That was yet another great tut indeed!
    I’ve got a doubt !
    When I output an address of a number,say 5 using &value,
    This is what I get : 0x22ff44
    But above for the address of 5 ,you’ve given this : 0012FF7C

    May I know what’s the difference b/w those if you don’t mind ?

    Waiting for your reply,
    Prajwal

  • Georges Theodosiou

    Mr Alex,
    Please permit me a comment: At http://www.tutorialspoint.com/cplusplus/cpp_pointers.htm , first sentence is:
    "C++ pointers are easy and fun to learn." I study c++ pointers for several days and feel that you are right on that:
    "Pointers are typically seen as one of the most confusing parts of the C++ language, but they’re surprisingly simple when explained properly.".
    I express my sincere gratitude for this sentence.

    With regards and friendship
    Georges Theodosiou

  • abolfazl

  • Abdul sami

    Dear Alex ,I hope you will be fine.

    I have a question about Arrays.

    If we declare an Array of any size for example

    Now  arr will become a pointer  point to the first element of arr[6].

    Now when we find the size arr  

    //Size of Array = 6

    why this is happening, the arr is an int type pointer point to the first element
    same problem in function argument

    • Alex

      arr doesn’t decay into a pointer when used with operator sizeof(), so sizeof() is able to access the array length.

      The size of the array isn’t 6, it’s 24 (6 elements * 4 bytes each).

  • Dragos

    I have something unclear here:

    the fuction has int *&p, but I tought when we use * with int we declare a pointer variable, so the name of the variable is "&p"? If not what that does mean? I hope you understand what I mean.

  • Pascal Kangberee

    Thank a lot.  Finally understand pointers. Great job

  • bert

    Typo:

    Pointer variables are declared just like normal variable,

    I believe you meant to type "normal variables"

  • Kılıçarslan

    Best explanation I have ever seen.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter