Search

6.8 — Pointers and arrays

Pointers and arrays are intrinsically related in C++.

Similarities between pointers and fixed arrays

In lesson 6.1 -- Arrays (part i), you learned how to define a fixed array:

To us, the above is an array of 5 integers, but to the compiler, array is a variable of type int[5]. We know what the values of array[0], array[1], array[2], array[3], and array[4] are (9, 7, 5, 3, and 1 respectively). But what value does array itself have?

The variable array contains the address of the first element of the array, as if it were a pointer! You can see this in the following program:

On the author’s machine, this printed:

The array has address: 0042FD5C
Element 0 has address: 0042FD5C

Note that the address held by the array variable is the address of the first element of the array.

It’s a common fallacy in C++ to believe an array and a pointer to the array are identical. They’re not. Although both point to the first element of the array, they have different type information. In the above case, array is of type “int[5]”, whereas a pointer to the array would be of type “int *”. We’ll see where this makes a difference shortly.

The confusion is primarily caused by the fact that in many cases, when evaluated, a fixed array will decay (be implicitly converted) into a pointer to the first element of the array. All elements of the array can still be accessed through the pointer, but information derived from the array’s type (such as how long the array is) can not be accessed from the pointer.

However, this also effectively allows us to treat fixed arrays and pointers identically in most cases.

For example, we can dereference the array to get the value of the first element:

Note that we’re not actually dereferencing the array itself. The array (of type int[5]) gets implicitly converted into a pointer (of type int *), and we dereference the pointer to get the value at the memory address the pointer is holding (the value of the first element of the array).

We can also assign a pointer to point at the array:

This works because the array decays into a pointer of type int *, and our pointer (also of type int *) has the same type.

Differences between pointers and fixed arrays

There are a few cases where the difference in typing between fixed arrays and pointers makes a difference. These help illustrate that a fixed array and a pointer are not the same.

The primary difference occurs when using the sizeof() operator. When used on a fixed array, sizeof returns the size of the entire array (array length * element size). When used on a pointer, sizeof returns the size of a memory address (in bytes). The following program illustrates this:

This program prints:

20
4

A fixed array knows how long the array it is pointing to is. A pointer to the array does not.

The second difference occurs when using the address-of operator (&). Taking the address of a pointer yields the memory address of the pointer variable. Taking the address of the array returns a pointer to the entire array. This pointer also points to the first element of the array, but the type information is different (in the above example, int(*)[5]). It’s unlikely you’ll ever need to use this.

Revisiting passing fixed arrays to functions

Back in lesson 6.2 -- Arrays (part ii), we mentioned that because copying large arrays can be very expensive, C++ does not copy an array when an array is passed into a function. When passing an array as an argument to a function, a fixed array decays into a pointer, and the pointer is passed to the function:

This prints:

32
4

Note that this happens even if the parameter is declared as a fixed array:

This prints:

32
4

In the above example, C++ implicitly converts parameters using the array syntax ([]) to the pointer syntax (*). That means the following two function declarations are identical:

Some programmers prefer using the [] syntax because it makes it clear that the function is expecting an array, not just a pointer to a value. However, in most cases, because the pointer doesn’t know how large the array is, you’ll need to pass in the array size as a separate parameter anyway (strings being an exception because they’re null terminated).

We lightly recommend using the pointer syntax, because it makes it clear that the parameter is being treated as a pointer, not a fixed array, and that certain operations, such as sizeof(), will operate as if the parameter is a pointer.

Recommendation: Favor the pointer syntax (*) over the array syntax ([]) for array function parameters.

An intro to pass by address

The fact that arrays decay into pointers when passed to a function explains the underlying reason why changing an array in a function changes the actual array argument passed in. Consider the following example:

Element 0 has value: 1
Element 0 has value: 5

When changeArray() is called, array decays into a pointer, and the value of that pointer (the memory address of the first element of the array) is copied into the ptr parameter of function changeArray(). Although the value in ptr is a copy of the address of the array, ptr still points at the actual array (not a copy!). Consequently, when ptr is dereferenced, the actual array is dereferenced!

Astute readers will note this phenomena works with pointers to non-array values as well. We’ll cover this topic (called passing by address) in more detail in the next chapter.

Arrays in structs and classes don’t decay

Finally, it is worth noting that arrays that are part of structs or classes do not decay when the whole struct or class is passed to a function. This yields a useful way to prevent decay if desired, and will be valuable later when we write classes that utilize arrays.

In the next lesson, we’ll take a look at pointer arithmetic, and talk about how array indexing actually works.

6.8a -- Pointer arithmetic and array indexing
Index
6.7a -- Null pointers

110 comments to 6.8 — Pointers and arrays

  • Hardik

    Here also, the array being passed doesn’t decay, no?
    Because then we wouldn’t have been able to change all of the elements of the array.

    • Alex

      The array does decay into a pointer when passed to the function. However, we can still use the pointer to modify the original array argument.

      • Hardik

        It means that the function parameter is also a pointer that is capable of holding the memory address of the array being passed !

  • C++

    Output :-
    0x60ff08
    0x60ff08
    0x60ff08

    Output :-
    0x60ff0c
    0x60ff0c
    0x60ff08

    Why The Outputs are different?
    Is it because it(in the 2nd case) produces the memory address of the ptr var rather than the var it is pointing to? Plz Explain !

    • Alex

      In the last example, you’re printing the address of variable ptr, not the address that ptr is holding (which is array’s address). It should be consistent if you change to this:

      • C++

        "Is it because it(in the 2nd case) produces the memory address of the ptr var rather than the var it is pointing to?"

        I said that btw ! But, Thanks 🙂 !
        No, I just wanted to experiment it !

  • James Ray

    The confusion is primary
    The confusion is primarily

  • nikos-13

    a) "When evaluated, a fixed array will “decay” into a pointer to the first element of the array. All elements of the array can still               be accessed through the pointer, but information derived from the array’s type can not be accessed from the pointer."

    What do you mean with "All elements of the array can still be accessed through the pointer", how could this happen?

    b) " Taking the address of the array returns a pointer to the entire array. This pointer also points to the first element of the array, but the type information is different (in the above example, int(*)[5])."

    What do you mean with "int(*)[5]"?

    • Alex

      1) I mean a pointer pointing at the first element of an array can be used just like the array itself can. For example:

      This works because of pointer arithmetic.

      2) Don’t worry about it for now. It’s not something you need to know to progress.

      • nikos-13

        Thank you Alex!

      • Nguyen

        Hi Alex,

        The last line (std::cout << ptr[1]; // will print 3 (value of element 1) is so strange to me.  

        In this chapter, I only see std::cout<<ptr & std::cout<<*ptr in the examples.

        • Alex

          We cover that usage in the very next lesson.

          • Nguyen

            Hi Alex,

            I’ve finished 6.8B & I don’t see it????  I don’t want to miss it.

            Thanks, Have a great day.

            • Alex

              I was referring to 6.8A, particularly the subsection titled, “Pointer arithmetic, arrays, and the magic behind indexing”

              • Nguyen

                Hi Alex,

                Based on what I’ve learned from 6.8A, it would make sense to me if the last line looked like in the following:

                int array[] = { 5, 3, 6, 7 };
                int *ptr = array;
                std::cout << array[1]; // will print 3 (value of element 1)
                std::cout << *(ptr + 1); // will print 3 (value of element 1)

                =====================================================

                Oh ok, I think I understand it now.  

                array[n] is the same as *(array + n); therefore, *(prt + 1) is the same as prt[1]. Yah!

                To me, prt[1] seemed very strange to me at first because I did not see it in the lesson.  It would be nice if it somehow was seen/mentioned in the examples.

                Thanks, Have a great day.

  • thang

    Why ???? it still printed 4

    //Finally, it is worth noting that arrays that are part of structs or classes do not decay when the whole struct or class is passed to a function. This yields a useful way to prevent decay if desired, and will be valuable later when we write classes that utilize arrays.

    #include

    struct new1
    {
    int a;
    };

    void printsize(new1 arr[]);

    int main()
    {
    new1 arr[5];
    printsize(arr);
    }
    void printsize(new1 arr[])
    {
    std::cout << sizeof(arr) << "n";
    }

    • Alex

      You created an array of structs rather than a struct containing an array.

      • thang

        // it is worth noting that arrays that are part of structs or classes do not decay when the whole struct or class is passed to a function.//

        I don’t understand why you said arrays do not decay when struct is passed to a function but in above code arr still has size is 4 provide that it decays in pointer…

        sorry for my bad english .))

        • Alex

          Because you’re code isn’t doing what I’m suggesting. 🙂 An array that is inside a struct will not decay:

          An array of structs will still decay:

  • Rohit

    Is there any way of passing and array into a function without decaying it except using struct or classes or some other thing, just passing it through main()?

    • Alex

      Yes, there is. You can pass an array by reference:

      But the syntax is messy. A better solution is just to use std::array. We cover std::array later in this chapter.

  • Milos

    Alex love your site so much it helped me a lot, i have one off topic quesiton,
    I have searched today a little bit on the internet and found out that visual studio 2012+ don’t support windows form applications, i also found out there is a way to go around it but i dont have a tools menu or things like that (if u understand me), so my questions are how do i create real life applications for windows with c++ and where also can i use my c++ knowledge for creating some real life programs?

    Thank you for everythig, you are the real HERO <3

    • Alex

      My understanding is that Windows Form applications are part of Microsoft .net, so you need to use managed C++ to create one. Unfortunately, I don’t have any knowledge on that topic, as I’ve never used .net (outside of some dabbling with C#).

  • Chrisenyle

    Hi, Alex
    I have a question for you. Give this code:

    ….

    I know this will print 20 (NumberOfElements * sizeof(int))
    But I want to ask that how can it know the size of the array?
    'Who' is holding the information of the array's length?

    Thanks

    • Alex

      When you compile your program, the compiler builds a symbol table full of variable names and types as it encounters variables. The sizeof operator is resolved at compile time, and the size itself can be derived from the variable’s type. So when you compile this program, the compiler will replace “sizeof(array)” with 20 (which it knows because it knows that array is an array of 5 integers).

  • raj

    why is my code failing?
    int* test();
    int main()
    {
    int* ptr=test();
    for(int i=0;i<3;i++)
    cout<<*(ptr+i)<<" ";

    }
    int* test()
    {
    int arr[3];
    arr[0]=10;
    arr[1]=20;
    arr[2]=30;
    return arr;

    }

    i am getting some garbage output instead of actual values in the array

    • Alex

      Variable arr is a local variable. That means it goes out of scope (and is destroyed) at the end of test.

      However, you’re passing the address of arr back to main(). By the time main() gets the address, arr has already been destroyed. Consequently, main() is accessing a pointer that is now pointing to garbage.

  • bert

    I think there’s an extra word this time:

    and we dereference the pointer to get the value at that the memory address the pointer is holding

    I think you meant to drop the "that"

    thanks!

  • kris

    First I’d like to thank you for this great site teaching everything about c++. But my problem is i want to learn everything how to write the program use a command prompt and eventually become good to able to code my own video games. I have more then 15 hours a day and this is great. Please provide a learning path or what to do or etc. So I’ll has a good perceptive of it all.

    I believe you have my email thanks!!!! krisgoku2@hotmail.com

    • Raquib

      Hey Kris,

      I am glad to see that you are passionate about learning how to code bottoms up, that’s necessary to start learning anything generally. I am not an expert but I might be able to share with you some suggestions that I received from many programmers over the years -

      1- Get your hands dirty- Just start coding. This site can help you with that. Do the exercises/quizzes at the end of the chapters to begin with. Learn a concept and apply it. Man everyone starts with a hello world. Every single programmer I came in touch with said me the same thing. Follow the best practices in every code you write until it becomes your second nature. So, to quote from a fender squier affinity series slogan "stop dreaming, start playing" 🙂 .

      2- Learn to interpret-  Another piece of advice I got when I asked a programmer from the compiler team(Hey Bryan! in case if he ever reads this)  - " What one piece of suggestion would you like to give me to become a good programmer like you? " . The answer was " Learn to understand what others have written, that’s one of the most useful skill to become good at programming". The reason you have to grow that skill is becoz, apart from writing code most of the time is spent debugging and maintaining a program. You will need to spend considerable amount of time looking and fixing others code, so it’s important to grow that skill early on. Apart from that some programs are well organized and some not at all, both will help you learn and become a better coder. A good code is one that is efficient, readable, re-usable and easily maintainable. On this site in the comment section there are so many coders posting there query, look at them, try to understand, see if you can answer them, if yes answer them. Trying to explain someone else increases your understanding. More importantly going through the comment section, answers a lot of questions you might have, may be opens a new dimension altogether you never thought about. Then there is stack overflow.

      3- Aim small miss small (from Patriot) - Don’t expect to learn everything in one day. Start slow, have small goals don’t rush. Since you have a lot of time, make sure you complete each chapter properly. Don’t jump coz these lessons have been organized after a lot of time spent on how to do it.  These concepts are very important and will teach you the core C++. Once done you will be capable enough to absorb new concepts and more advanced topics. Which will require time, and lots of coding experience.

      Best of luck. Happy coding 🙂

      Regards,
      Raquib

  • Hi Alex,

    I have a Query. I am Checking the below Program.

    #include <iostream>

    int main()
    {
        using namespace std;
        int array[5] = {1,6,9,5,7};
        
        std::cout << &array << "n" << &array[0];
        std::cout << ‘\n’;
        std::cout << *(&array) << "n" << *(&array[0]);
        return 0;
    }

    When I run this program, I got the address for the first element of the array in both the cases(for the first cout). I understand the reason, As you rightly said: "The only difference is the type information that is returned. A pointer to the first element would have type int*, whereas a pointer to the whole array would have type (int[5] *).".

    However, for the third cout, I am trying to dereference "&array" and "&array[0]".

    So while dereferenceing, For "&array[0]", I got the correct result, i,e 1.
    But for "&array", I got the memory address of the "array" again after dereferencing in stead of the array element.

    I couldn’t understand the reason for this. Could you please explain, why *(&array) evaluated to memory address of the array rather then value of the array ?

    • Alex

      Remember that array decays to a pointer of some kind, and [] has an implicit deference. So:
      *(&array[0]) evaluates array[0], giving you the value of element 0, which you then take the address of (giving you a pointer), which you then dereference to get the value of element 0 again.
      *(&array) evaluates &array, which takes the address of the pointer to the array, essentially giving you a pointer to a pointer. You then dereference this to get back the original pointer to the array. This is why you’re getting an address here.

      I think what you meant to do was this:

      On the left hand side, *array dereferences the pointer to the array, giving you the value of element 0.

  • Jason

    What do you think of the following syntax for passing arrays to a function?

    • Alex

      It generally won’t work, unless arraySize is a macro. arraySize has to be a integer literal -- strangely enough, constexpr variables don’t seem to work here.

  • abolfazl

  • Darren

    I remember there being some obscure syntax about arrays. Something like that myArray[n] is equivalent to *(myArray + n) which is equivalent to *(n + myArray) such that a statement like n[myArray], where n is an integer representing an array index, is actually valid syntax for access to the (n - 1)th array element. Not that you’d want to use such an odd thing.

Leave a Comment

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