0

Please help me understand what happens here:

#include <iostream>

void foo(int *ar) {std::cout << sizeof(arr) << '\n' << arr[3];} // exceeding array bounds on purpose 

int main()
{
   int arr[2]{3, 5};
   foo(arr);

   return 0;
} 

Is this an example of array decay? And what exactly is *arr? Is it a pointer-to-int, or is it a pointer-to-array (of int)? In case of the latter, does it carry information about the address of a memory block holding the array? If not, how is it possible to use array notation inside a function that only recieves a pointer to its first element?

Then,

#include <iostream>

void foo(int *ar) {std::cout << sizeof(arr) << '\n' << arr[1];}

int main()
{
   int arr[2][1]{{3}, {5}};
   foo(*arr);

   return 0;
} 

What happens in case of a 2D array? What does *arr represent here when passed? Is it the pointer to the first element of the right array? What does it represent when taken as an argument by a function?

edit: changed array name in foo

6
  • int *arr is a pointer to a single int. The question would be more clear if you would give different names to arr in main and arr in foo Commented Nov 9, 2022 at 14:15
  • Is it a pointer-to-int, -- void foo(int *arr) --> It should be clear what it is, as it says right there what it is. It can't be anything else. Commented Nov 9, 2022 at 14:16
  • 2
    Why put all the effort in understanding pointer decay when you can use std::array and/or std::vector. In my experience using "C" style arrays only leads to bugs Commented Nov 9, 2022 at 14:16
  • arr[3] is syntactic sugar for *(arr + 3). You could even do 3[arr] for fun, but don't do that in real code. Commented Nov 9, 2022 at 14:16
  • 1
    In the second, *arr is equivalent to arr[0], which is an array with one element. That array behaves exactly like all other arrays. Commented Nov 9, 2022 at 15:20

1 Answer 1

2

Yes, that is an example of an array decaying into a pointer.

int* arr is a pointer to the first element of the array. The address is guaranteed to be the same as the address of the array, but the type is different.

In foo(*arr), you are dereferencing a int[2][1], an array of 2 elements where each element is an array of 1 element. This gives you a int(&)[1] - a reference to an array of one elements. This then decays to a pointer to the first element of the 1 element array.

Now, why does int*arr; arr[2] work? Well, ptr[n] in C and C++ is defined to mean *(ptr+n). So much so that n[ptr] works (!). (do NOT do n[ptr] ever)

Array indexing on normal arrays even works this way. int arr[3]; arr[2] is actually doing a decay-of-array-to-pointer, then doing +2 on that pointer, then dereferencing.

C was designed as a slightly portable assembly language. And in assembly, array indexing is adding (with some multiplication) then a load instruction.

pointer + int in this model converts both to ints, then scales the int by the size of the pointed to thing, adds them up, then converts back to pointers and does a load.

The C++ and C standards doesn't actually say this is what is going on, because they both talk about things more abstractly to permit a variety of implementations to exist. But that is the model they are based off of.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.