Search

6.8 — Pointers and arrays

Pointers and arrays are intrinsically related in C++.

Array decay

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

In all but two cases (which we’ll cover below), when a fixed array is used in an expression, the fixed array will decay (be implicitly converted) into a pointer that points to the first element of the array. You can see this in the following program:

On the author’s machine, this printed:

Element 0 has address: 0042FD5C
The array decays to a pointer holding address: 0042FD5C

It’s a common fallacy in C++ to believe an array and a pointer to the array are identical. They’re not. In the above case, array is of type “int[5]”, and it’s “value” is the array elements themselves. A pointer to the array would be of type “int *”, and its value would be the address of the first element of the array.

We’ll see where this makes a difference shortly.

All elements of the array can still be accessed through the pointer (we’ll see how this works in the next lesson), 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

169 comments to 6.8 — Pointers and arrays

  • Harshit

    Hi Alex,

    Here in my code, I can see that an array in char does not decay into pointers whereas an array of int type does. Why does this happen?

  • Jeff

    Hi Alex.

    You mentioned that Arrays in structs and classes don’t decay... But I have some code here that shows me the array is decaying. What am I not understanding here?

  • Behzad

    I would suggest adding this code to clarify the effect of address-of operator (&) on an array:

  • Lakshya Malhotra

    Hi,
    I can't explain what's going on with my code. So I am trying to print the length of a C-string and then output the string itself. My code is outputting the length fine but it is not printing the string.

  • Jagadeesh Takkalaki

    What is the problem with above code? I am not getting entire string as output.It is printing only characters of string until space, not printing character after space.
    Expected value of ptr1:RAM SHAM BAM
    Present Output:RAM

    • * Line 7, 18, 19, 20, 32, 33: Initialize your variables with brace initializers. You used copy initialization.
      * Line 2: Initialize your variables with brace initializers.
      * Use ++prefix unless you need postfix++.
      * Don't use "using namespace".
      * Use the auto-formatting feature of your editor.
      * Line 22: Should be &&, not ||.
      * Enable compiler warnings, read them, fix them.

  • Now since <type>* and <type>[] will as parameters just pass the pointer, I did put things on the test with <type>[<length>].

    And the result was this:

    I suppose that this method DOES copy the array as a whole into the function, or am I wrong?

    • Alex

      Built-in arrays work strangely in C/C++. In such a case, the array parameter is treated as a pointer to an array, and the size information is discarded. So the array isn't copied, just the pointer to the array is copied.

      If you want to retain the type information, pass the array by reference, or better, use std::array.

  • Bad_at_Coding

    Not that this one is going to be important, but we can actually change the following

    to

  • Doug

    "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:"

    I'm not sure this is correct.  That program demonstrates decay to a pointer, nothing more.

    An array variable no more contains an address than a structure variable contains the address of the structure or an integer variable contains the address of the integer.  Instead, an array variable contains the contents of the array, just like a structure variable contains the contents of the structure.

  • Minh

    hey, i want to ask a pretty simple thing
    let us have a data structure like

    I have the pnode A's left is B and right is C. A's parent is X.
    I want to swap B to be the parent of A. So B->(A)->C
    When I do this

    What I want to do is target's parent will point to X's parent but X remain X, but the node X change into X's parent too, so how to point target's parent to X's parent. :(
    Thank you in advance.

  • Jack

    Hi guys,
    Can you just tell me what does this mean in more detail?
    (strings being an exception because they’re null terminated).
    and how could I pass the length of an array in a seperate parameter?

    • Alex

      Because strings always end in a '\0' character, we don't necessarily need to know the length of a string to know where it ends. Instead, we can keep going until we run into the '\0'.

      This doesn't work for other arrays because those arrays don't typically have an element that signals termination.

      > how could I pass the length of an array in a seperate parameter?

      Add an "int length" parameter to your function. If you know the array's length already, you can pass it as an argument. If you don't know it but your array is a fixed array, you can use the sizeof(array)/sizeof(array[0]) trick to get the length. If you have a dynamic array and you don't know the length, you're out of luck.

Leave a Comment

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