Navigation



6.7 — Introduction to pointers

Pointers are one of the most powerful and confusing aspects of the C language. A pointer is a variable that holds the address of another variable. To declare a pointer, we use an asterisk between the data type and the variable name:

int *pnPtr; // a pointer to an integer value
double *pdPtr; // a pointer to a double value

int* pnPtr2; // also valid syntax
int * pnPtr3; // also valid syntax

Note that an asterisk placed between the data type and the variable name means the variable is being declared as a pointer. In this context, the asterisk is not a multiplication. It does not matter if the asterisk is placed next to the data type, the variable name, or in the middle — different programmers prefer different styles, and one is not inherently better than the other.

Since pointers only hold addresses, when we assign a value to a pointer, the value has to be an address. To get the address of a variable, we can use the address-of operator (&):

int nValue = 5;
int *pnPtr = &nValue; // assign address of nValue to pnPtr

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

It is also easy to see using code:

int nValue = 5;
int *pnPtr = &nValue; // assign address of nValue to pnPtr

cout << &nValue << endl; // print the address of variable nValue
cout << pnPtr << endl; // print the address that pnPtr is holding

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:

int nValue = 5;
double dValue = 7.0;

int *pnPtr = &nValue; // ok
double *pdPtr = &dValue; // ok
pnPtr = &dValue; // wrong -- int pointer can not point to double value
pdPtr = &nValue; // wrong -- double pointer can not point to int value

Dereferencing pointers

The other operator that is commonly used with pointers is the dereference operator (*). A dereferenced pointer evaluates to the contents of the address it is pointing to.

int nValue = 5;
cout << &nValue; // prints address of nValue
cout << nValue; // prints contents of nValue

int *pnPtr = &nValue; // pnPtr points to nValue
cout << pnPtr; // prints address held in pnPtr, which is &nValue
cout << *pnPtr; // prints contents pointed to by pnPtr, which is contents of nValue

The above program prints:

0012FF7C
5
0012FF7C
5

In other words, when pnPtr is assigned to &nValue:
pnPtr is the same as &nValue
*pnPtr is the same as nValue

Because *pnPtr is the same as nValue, you can assign values to it just as if it were nValue! The following program prints 7:

int nValue = 5;
int *pnPtr = &nValue; // pnPtr points to nValue

*pnPtr = 7; // *pnPtr is the same as nValue, which is assigned 7
cout << nValue; // prints 7

Pointers can also be assigned and reassigned:

int nValue1 = 5;
int nValue2 = 7;

int *pnPtr;

pnPtr = &nValue1; // pnPtr points to nValue1
cout << *pnPtr; // prints 5

pnPtr = &nValue2; // pnPtr now points to nValue2
cout << *pnPtr; // prints 7

The null pointer

Sometimes it is useful to make our pointers point to nothing. This is called a null pointer. We assign a pointer a null value by setting it to address 0:

int *pnPtr;
pnPtr = 0; // assign address 0 to pnPtr

or shorthand:

int *pnPtr = 0;  // assign address 0 to pnPtr

Note that in the last example, the * is not a dereference operator. It is a pointer declaration. Thus we are assigning address 0 to pnPtr, not the value 0 to the variable that pnPtr points to.

C (but not C++) also defines a special preprocessor define called NULL that evaluates to 0. Even though this is not technically part of C++, it’s usage is common enough that it will work in every C++ compiler:

int *pnPtr = NULL; // assign address 0 to pnPtr

Because null pointers point to 0, they can be used inside conditionals:

if (pnPtr)
    cout << "pnPtr is pointing to an integer.";
else
    cout << "pnPtr is a null pointer.";

Null pointers are mostly used with dynamic memory allocation, which we will talk about in a few lessons.

The size of pointers

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

char *pchValue; // chars are 1 byte
int *pnValue; // ints are usually 4 bytes
struct Something
{
    int nX, nY, nZ;
};
Something *psValue; // Something is probably 12 bytes

cout << sizeof(pchValue) << endl; // prints 4
cout << sizeof(pnValue) << endl; // prints 4
cout << sizeof(psValue) << endl; // prints 4

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.

Quiz

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

short nValue = 7; // &nValue = 0012FF60
short nOtherValue = 3; // &nOtherValue = 0012FF54
short *pnPtr = &nValue;

cout << &nValue << endl;
cout << nValue << endl;
cout << pnPtr << endl;
cout << *pnPtr << endl;
cout << endl;

*pnPtr = 9;

cout << &nValue << endl;
cout << nValue << endl;
cout << pnPtr << endl;
cout << *pnPtr << endl;
cout << endl;

pnPtr = &nOtherValue;

cout << &nOtherValue << endl;
cout << nOtherValue << endl;
cout << pnPtr << endl;
cout << *pnPtr << endl;
cout << endl;

cout << sizeof(pnPtr) << endl;
cout << sizeof(*pnPtr) << endl;

Quiz solutions

1) Show Solution

6.8 — Pointers, arrays, and pointer arithmetic
Index
6.6 — C-style strings

22 comments to 6.7 — Introduction to pointers

  • [...] the lesson on pointers, you learned that a pointer is a variable that holds the address of another variable. Function [...]

  • Cody

    In the code

    if (pnPtr)
        cout < < "pnPtr is pointing to an integer.";
    else
        cout << "pnPtr is a null pointer.

    you forgot the second double quotation mark and a semicolon.

  • 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. :)

  • Aaron

    Example is wrong. Look at cody’s comment above.

    [ How did I miss that? Wow. Thanks, it's fixed. -Alex ]

  • [...] 6.7 — Introduction to pointers [...]

  • 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.

  • [...] 2007 Prev/Next Posts « 6.7 — Introduction to pointers | Home | 6.9 — Dynamic memory allocation with new and delete » Wednesday, July [...]

  • 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

  • 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).

  • Hamza K

    I don’t understand this statement, shouldn’t it be the other way around?:

     int *pnPtr = 0;  // assign address 0 to pnPtr 

    “Note that in the last example, the * is not a dereference operator. It is a pointer declaration. Thus we are assigning address 0 to pnPtr, not the value 0 to the variable that pnPtr points to.”

    When I use the following code:

     int * pnPtr = 0;
    cout << &pnPtr << endl;
    cout << pnPtr << endl; 

    I get the output
    0013FF60
    00000000

    surely the address is 0013FF… and the value is 000?

    Many thanks for the tutorials though, they’re amazing, you’re a saint!

    • Simon Kazakov

      The statement is okey. Assigning an address to a pointer means that u tell the pointer: “Point to this address”. This is done with the “&”.

       int a = 10;
      int *ptr = &a;
      // the * is not a dereference operator. It is a pointer declaration.

      U can change the value of the pointed object with “*”.

       *ptr = 8; // changes a to 8 

      The pointer itself is a variable that has an address. It is impossible to have a variable at 0000 0000.

    • baldo

      00000000 is not the value. See this:

      cout << &pnPtr << endl;  // will print the address of the pointer (0013FF60)
      cout << pnPtr << endl;   // will print the address that the pointer points to (00000000)
      cout << *pnPtr << endl;  // will print the value of the address that the pointer points to
      

      Because the pointer is null, it is pointing to address 00000000. The address of the pointer is 0013FF60.

  • 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.

  • [...] So within our ParticleEmitter declaration we’ve declared that we’re going to have an x and y value to position our emitter on the screen and a rotation value to rotate the emitter over time. We also declare three methods, setup, update, and draw that will define what our emitter will do every time the application cycles through a frame. Lastly we declare an Array called “p” that will store all of the Particles that are currently on the screen. The pointer syntax(*) that declares the “p” array is out of the scope of this article, however you can learn about pointers and how they work in C++ via this excellent tutorial here. [...]

  • 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;

You must be logged in to post a comment.