Search code examples
c++arrayspointersmemoryallocation

If arr[3] is an array and ptr is a pointer, then why do arr and &arr give same result but ptr and &ptr don't


I am a beginner to data structures and algorithms, started studying the pointers now and before asking the question here I read this recommended post but I couldn't understand it so I am asking the query here.

I have been told by a friend that array's name is a pointer to the first value in the array, as arr returns the address of arr[0], arr+1 returns address of arr[1], so when I write this

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int i = 10;
    int arr[3] = {1, 2, 3};
    int *ptr = &i;
    cout << arr << "   " << &arr << endl;
    cout << ptr << "   " << &ptr;
    return 0;
}

Both arr and &arr give same result

0x61ff00 0x61ff00

While ptr and &ptr give different results

0x61ff0c 0x61fefc

Can someone tell me why is this happening ?


Solution

  • Arrays are not pointers!

    Arrays do decay to a pointer to their first element in all sorts of circumstances. For example std::cout << arr; actually prints the memory address of the first element of the array. std::cout << &arr; prints the memory address of the array. As the address of the first element is the same as the address of the array you see the same value.

    However, just because they have the same value, does not mean they are the same. arr can decay to a int*, while &arr is a pointer to an array, a int(*)[3].

    I hope the following will help to clear things up a little:

    #include <iostream>
    #include <type_traits>
    
    
    void make_it_decay(int x[]) {
        std::cout << std::is_same_v< decltype(x), int*> << "\n";
    }
    
    int main() {
        int arr[3] = {1,2,3};
    
        //std::cout << (arr == &arr) << "\n";  // does not compile !
        std::cout << (arr == &(arr[0])) << "\n";
    
        std::cout << std::is_same_v< decltype(arr), int[3]> << "\n";
        std::cout << std::is_same_v< decltype(&arr),int(*)[3]> << "\n";
        std::cout << std::is_same_v< decltype(&arr[0]), int* > << "\n";
        make_it_decay(arr);
    }
    

    output:

    1
    1
    1
    1
    1
    

    I use decltype to infer the type of certain expressions and std::is_same_v to see if the expressions are of same type.

    arr is of type int[3]. It is an array. It is not a pointer.

    &arr is the address of the array. It is a pointer to an array with three elements, a int(*)[3].

    &arr[0] even though it has the same value as &arr is of different type. It is a pointer to int, an int*.

    When we pass arr to a function then it decays to a pointer to the first element of the array. And we can see that inside the function x is int*.


    Now to your quesiton...

    Above I tried to lay out what happens when you write std::cout << arr. Pointers are different, because ... well arrays are not pointers.

    std::cout << ptr;  // prints the value ptr
    std::cout << &ptr; // prints the address of ptr
    

    Perhaps some visualization helps. The difference in types gets most apparent when incrementing the pointers

     -------------------
     | arr             |
     -------------------
     |  1  |  2  |  3  |
     -------------------
       ^       ^         ^
       &arr    |         &arr + 1 
       &arr[0] |
               &arr[0] + 1