arrays and pointers

Hello, I am learning about arrays and pointers, and there is one part that I am stuck on and no matter how much I read, I still can not figure it out. My book said that arrays decay to pointers. So, the way I am thinking it works is when I declare an array, a pointer is also created that points to the first element in the array and the name of the pointer is the same name of the array, is this correct? And if I am, what then happens if I create another pointer and assign the array to that pointer (like shown below)? Do I end up with a pointer pointing to a pointer?

And then what is the point in assigning a pointer to an array, like my book has taught, if the array is technically already a pointer. Unfortunately the book I am using does not really give a lot of detail on this array to pointer decay, it only says that it happens. I have read a lot over different sites, but as I said, I seem to be really struggling to understand this concept.

1
2
3
4
  int array[5];
  int *pointer;

  pointer = array;
Within the function in which the array is declared, the array name can be thought of as representing two kinds of information: the address of the first element of the array, and the size of the array. When you pass an array to a function, it loses the size information and becomes a pointer.

if I create another pointer and assign the array to that pointer ... Do I end up with a pointer pointing to a pointer?

No. You end up with a pointer that contains the beginning address of the array, which is exactly what happens when you pass an array to a function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

void f(int a[]) // the size information is not needed
                // it's ignored if you include it like int a[10]
                // You could even say int a[99] and it will be ignored.
                // You could also declare it as int *a.
{
    std::cout << sizeof(a) << '\n'; // prints 8 (assuming 8-byte pointers)
}

int main()
{
    int a[10];
    std::cout << sizeof(a) << '\n';  // prints 40 (assuming 4-byte ints)
    f(a);

    int *b = a;  // b contains the address of ("points to") the first element of a
    f(b);
}

Last edited on
it is really sort of a friendly syntax to save you having to say
pointer = &(array[0]); //same thing, annoying to type

you are over-thinking it.
a pointer is not created when you define an array. An array is just a sequential block of bytes in ram, tied to the name you gave it. If you take the address of that block, its a pointer, so the compiler can easily convert an array to a pointer. Internally, the compiler already has this address tied to the name, so its a tiny hop to pointerify it.

it isnt a pointer to a pointer or anything like that. Its just memory in ram, and you can take a pointer to that location. If it were a pointer to pointer you would have to say
int ** p;
p = array; //no good, types are wrong!

there are a few tricks you can use with this concept.
1 is parameters to functions
void foo (int* ip); //this function can accept an array OR a pointer-array (p = new thing[size])

2 is iteration:
loop of some kind..
.... use pointer;
pointer++; //moves to next array location. this is admittedly silly until you see iterators. A lot of built in c++ tools use this concept, or look up range-based for loop.

3) avoiding dynamic memory. you can allocate an array and use its pointer-ness to work with things that expect pointers, without having to fool with dynamic memory. This is really the same as point #1, but its worth the mention that many interfaces want raw pointers and dynamic memory is often overkill when an array will do.

Keep in mind that most modern c++ avoids both pointers and raw arrays. The containers do most of the things that we used to do with pointers, and vector objects / strings/ and a few other tools replace array heavy code. There are still places for the occasional pointer or array, but its not all through code everywhere (this is an older style closer to C that still compiles but is not used due to better tools).

one final way to think of it:
you know how you can assign compatible types, like int x = 'z' ? The compiler knows to turn the letter into an integer here. The same is true with array to pointer: the compiler knows what you mean, and does the necessary things to make it so.
Last edited on
when I declare an array, a pointer is also created that points to the first element in the array and the name of the pointer is the same name of the array,
When you declare the array (line 1 of your code), you have only created an array. It is not a pointer in itself, but implicitly decays into a pointer when used as such.

Your 'array' variable is not a pointer. It is, in fact, an array. 'array' is an array of 5 ints.
However, the decay happens when the array is used like a pointer, or passed into a function (by value), or dereferenced, which is to say almost every circumstance (but not all of them).

And if I am, what then happens if I create another pointer and assign the array to that pointer (like shown below)
Assigning a pointer to another pointer does not make it a pointer to a pointer, it just copies the value of the pointer, which is the address it points to.

If we take arrays out of the equation, what we have is something like this:
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main()
{
    int foo = 42;
    
    int* pfoo = &foo;
    int* another_pfoo = pfoo;
    
    std::cout << (*pfoo) << '\n';
    std::cout << (*another_pfoo) << '\n';
}

42
42


another_pfoo is still just a normal pointer, not a pointer to a pointer. To create a pointer to a pointer, you would need to take the address of an existing pointer variable.
1
2
3
4
5
6
int main()
{
    int   my_int        = 100;
    int*  my_ptr        = &my_int;
    int** my_ptr_to_ptr = &my_ptr;
}


And then what is the point in assigning a pointer to an array
You can't assign a pointer to an array. That would be a compiler error. Try it yourself (click on the gear symbol next to the code to run it in cpp.sh).

1
2
3
4
5
6
7
8
9
int main()
{
    int array[5] {};
    
    int some_data = 12345;
    int* ptr = &some_data;
    
    array = ptr; 
}
main.cpp: In function ‘int main()’:
main.cpp:8:13: error: incompatible types in assignment of ‘int*’ to ‘int [5]’
     array = ptr;
             ^~~


I assume you meant, why assign an array to a pointer? Indeed, it's not really necessary. It was probably just shown to you for demonstration purposes.

When you do int* ptr = array; the array decays into a pointer here, and what you're left with is a pointer to the first element of the array, and this pointer's value (the address) is copied into ptr.


Here is another notable difference between an array and a pointer.
1
2
3
4
5
6
7
8
9
10
#include <iostream>
int main()
{
    int array[5] {};
    
    int* ptr = array;
    
    std::cout << sizeof(array) << '\n';
    std::cout << sizeof(ptr) << '\n';
}

sizeof(array) most likely prints 20 for you. This is because array is an array of 5 ints, and sizeof(int) is most likely 4. So it's doing sizeof(int) * 5, or 4 * 5 = 20.
sizeof(ptr) is printing the size of an int-pointer on your system, which is most likely 8 if you're compiling as 64-bit.
Last edited on
"Arrays decay into pointers" is basically a reminder of two rules:

1. function parameters that have the type "array of T", where T is any type, are silently replaced with parameters of type pointer-to-T.
For example, in the function declaration
void f(int x[])
the parameter int x[], whose type is "array of int", is silently replaced with int *x - "pointer to int".

Therefore, void f(int x[]) is identical to void f(int *x) because of this rule.
It doesn't matter whether you specify an array size, either: void g(float x[12]) is identical to void g(float *x) for the same reason.

This is true even for complicated types like arrays of arrays, which can be mystifying. For example, in the function declaration
void h(int x[3][4])
the parameter int x[3][4], whose type is "array of 3 arrays of 4 ints" is silently replaced with int(*x)[4], which is "pointer to array of 4 ints".

2. Arrays can be silently treated as a pointer to their first element. For example, given the declaration
int x[3];
The compiler can treat x, whose type is "array of 3 ints", as a pointer to the first element of that array, which is a pointer to int:
int *y = x;
This process is called implicit conversion, and it works even for complicated types like arrays of arrays. Given
int x[3][4]
an array of 3 arrays of 4 ints, x can be implicitly treated as a pointer to the first element of that array, which is a pointer to array of 4 ints:
int (*y)[4] = x;

This particular conversion is called the array-to-pointer conversion.
Last edited on
@mbozzi: Aren't those int (*z)[4]?
And if I am, what then happens if I create another pointer and assign the array to that pointer (like shown below)? Do I end up with a pointer pointing to a pointer?


pointer will hold the start or first memory address of array - &array[0] or in other words "point to" the first value in array,

a pointer to a pointer is a little different

1
2
3
4

int a = 5;
int* p_a = &a;
int** p_p_a = &p_a


a is a variable with the value 5, a will also have a memory address, a pointer holds a memory address as it's value and itself has its own memory address, so if we set p_a = a, this is not valid as we cannot assign an int to p_a which expects a memory address, so we use the address of operator.

now p_p_a is a pointer to a pointer, what does this mean? p_p_a expects an address of a pointer, if we did p_p_a = &a, this would not be valid as a is not a pointer rather an int so it expects the address of &p_a

And then what is the point in assigning a pointer to an array, like my book has taught, if the array is technically already a pointer. Unfortunately the book I am using does not really give a lot of detail on this array to pointer decay, it only says that it happens. I have read a lot over different sites, but as I said, I seem to be really struggling to understand this concept.


Arrays decay into pointers yes, but arrays and pointers are not exactly the same thing, for example

1
2
3
4

int* arr = new int[4]; // valid 
int arr2[] = new int[4]; // not valid



Last edited on
@mbozzi: Aren't those int (*z)[4]?

Yes, thanks.
Hey thank you for all the answers, I believe I am beginning to grasp the concept of it now. All of your answers were very detailed and has definitely helped me out.
Topic archived. No new replies allowed.