Search

6.8a — Pointer arithmetic and array indexing

Pointer arithmetic

The C++ language allows you to perform integer addition or subtraction operations on pointers. If ptr points to an integer, ptr + 1 is the address of the next integer in memory after ptr. ptr - 1 is the address of the previous integer before ptr.

Note that ptr + 1 does not return the memory address after ptr, but the memory address of the next object of the type that ptr points to. If ptr points to an integer (assuming 4 bytes), ptr + 3 means 3 integers (12 bytes) after ptr. If ptr points to a char, which is always 1 byte, ptr + 3 means 3 chars (3 bytes) after ptr.

When calculating the result of a pointer arithmetic expression, the compiler always multiplies the integer operand by the size of the object being pointed to. This is called scaling.

Consider the following program:

On the author’s machine, this output:

0012FF7C
0012FF80
0012FF84
0012FF88

As you can see, each of these addresses differs by 4 (7C + 4 = 80 in hexadecimal). This is because an integer is 4 bytes on the author’s machine.

The same program using short instead of int:

On the author’s machine, this output:

0012FF7C
0012FF7E
0012FF80
0012FF82

Because a short is 2 bytes, each address differs by 2.

Arrays are laid out sequentially in memory

By using the address-of operator (&), we can determine that arrays are laid out sequentially in memory. That is, elements 0, 1, 2, … are all adjacent to each other, in order.

On the author’s machine, this printed:

Element 0 is at address: 0041FE9C
Element 1 is at address: 0041FEA0
Element 2 is at address: 0041FEA4
Element 3 is at address: 0041FEA8

Note that each of these memory addresses is 4 bytes apart, which is the size of an integer on the author’s machine.

Pointer arithmetic, arrays, and the magic behind indexing

In the section above, you learned that arrays are laid out in memory sequentially.

In lesson 6.8 -- Pointers and arrays, you learned that a fixed array can decay into a pointer that points to the first element (element 0) of the array.

Also in a section above, you learned that adding 1 to a pointer returns the memory address of the next object of that type in memory.

Therefore, we might conclude that adding 1 to an array should point to the second element (element 1) of the array. We can verify experimentally that this is true:

Note that when dereferencing the result of pointer arithmetic, parenthesis are necessary to ensure the operator precedence is correct, since operator * has higher precedence than operator +.

On the author’s machine, this printed:

0017FB80
0017FB80
7
7

It turns out that when the compiler sees the subscript operator ([]), it actually translates that into a pointer addition and dereference! Generalizing, array[n] is the same as *(array + n), where n is an integer. The subscript operator [] is there both to look nice and for ease of use (so you don’t have to remember the parenthesis).

Using a pointer to iterate through an array

We can use a pointer and pointer arithmetic to loop through an array. Although not commonly done this way (using subscripts is generally easier to read and less error prone), the following example goes to show it is possible:

How does it work? This program uses a pointer to step through each of the elements in an array. Remember that arrays decay to pointers to the first element of the array. So by assigning ptr to name, ptr will also point to the first element of the array. Each element is dereferenced by the switch expression, and if the element is a vowel, numVowels is incremented. Then the for loop uses the ++ operator to advance the pointer to the next character in the array. The for loop terminates when all characters have been examined.

The above program produces the result:

Mollie has 3 vowels
6.8b -- C-style string symbolic constants
Index
6.8 -- Pointers and arrays

100 comments to 6.8a — Pointer arithmetic and array indexing

  • Abraham

    What means the expresion

    exactly?
    When we declare not a poiter we had something like

    Why we have to add

    here?

    • nascardriver

      Hi Abraham!

      @ptr is a number. Example: Let's say @ptr is 0xA7E0. That's the address of the name. Here's what the memory from that address onward looks like:

      We only want to loop to the end of the string. So we need to keep looping as long as (ptr < 0xA7E7). 0xA7E7 is (0xA7E0 + 0x07) which is (name + arrayLength).

      The loop could be reduced to

      , because the last byte will always be 0.

  • Omkar

    const int arrayLength = 7;
    char name[arrayLength] = "Mollie";
    int numVowels(0);
    for (char *ptr = name; ptr < name + arrayLength; ++ptr)
    {
        switch (*ptr)
        {
            case 'A':
            case 'a':
            case 'E':
            case 'e':
            case 'I':
            case 'i':
            case 'O':
            case 'o':
            case 'U':
            case 'u':
                ++numVowels;
        }
    }

    cout << name << " has " << numVowels << " vowels.\n";

    for this example shouldn't the for loop termination condition be ptr < name + (arrayLength-1); ? Since the loop also checks the null terminator of the char array ? is that necessary

  • Santi

    Hi Alex,

    Which is the diference between std::endl and "\n"?
    I read it before in other chapter, but I can't find it.

    Thank you for the tutorial and the support that you provide! 🙂

    • nascardriver

      Hi Santi!

      When you use std::cout the input you give it is stored in a buffer. That buffer is regularly cleared and it's contents are displayed in the console. When you use '\n' the newline character will be inserted in the buffer and remain there until the next update occurs. When using std::endl the buffer is flushed immediately and your text is displayed.
      '\n' is faster than std::endl but you might not see your text right away.
      If you want to print multiple lines, you can use '\n' for every but the last line and use std::endl for the last line.

  • Kushagra

    #include <iostream>

    int main()
    {
        const char *myName = "Alex";
        std::cout << myName;

        return 0;
    }

    in this, how can you initialize a pointer with a string? pointer should be initialized with address. make me clear about this.

    • Kushagra

      And why do you use const here?
      what would be the result without const?

      • Alex

        "Alex" is a string literal. If myName was non-const, then you could try to modify "Alex", which will lead to undefined results. Making it const enlists the compiler's help in ensuring we don't try to modify the literal.

    • Alex

      "Alex" is a string literal. String literals have special handling. They are stored in a special part of memory, and are given a memory address. So you can initialize a char pointer with the address of a string literal.

  • Kushagra

    cout << name << " has " << numVowels << " vowels.\n";

    in this , name is an array then why don't it outputs the address of its first element?

  • heyjuhua

    hi alex, when i declare a pointer such as

    can i say that ptr is the pointer pointing to a pointer? thanks

    Also, one more question for the

    you put arrayLength = 7 is that because of we need one more index for ''? Thanks so much !

    • Alex

      1) No. ptr is a pointer pointing to an array of 3 integers.
      2) Yes, the array length needs to be large enough to hold the null terminator, otherwise crazy things will happen when we try to print the name or do anything else that is expecting the null terminator to be there.

  • Ameen

    ptr < name + arrayLength;

    can you please explain me this line.

    • heyjuhua

      Hi, I think that means

      the same thing. which is the array[0] + arrayLength so totally 7 indexes there. I am not sure if I am right.

    • Alex

      name is the address of the start of the array. arrayLength is the number of elements in the array. so name + arrayLength uses pointer arithmetic to find the address of the element that is just beyond the end of the array.

      If ptr is initially set to name, then we can increment ptr to step through the array, and continue doing so as long as ptr < name + arrayLength. As soon as ptr == name + arrayLength, we know we've gone off the end of the array and should stop iterating.

  • antiriad7

    Hello,

    Why doesn't this work?

    "No operator ">>" matches this operand:
    operand types are: std::istream >> std::string"

  • shannon

    So I was a bit confused with the switch loop, so I *think* I made it a bit more readable for some folks. Instead of declaring and initializing the ptr and declaring it inside the loop, it is outside now and just uses int i = 0 and i < arraylength (which equals 7). Hope this helps someone!

    int main()
    {
        const int arrayLength = 7;
        char name[arrayLength] = "Mollie";
        int numVowels(0);
        char *ptr = name;
        for (int i = 0; i < arrayLength; ++i, ++ptr)
        {
            switch (*ptr)
            {
                case 'A':
                case 'a':
                case 'E':
                case 'e':
                case 'I':
                case 'i':
                case 'O':
                case 'o':
                case 'U':
                case 'u':
                    ++numVowels;
            }
        }
        
        cout << name << " has " << numVowels << " vowels.\n";
        return 0;
    }

Leave a Comment

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