Using 'range for' for multidimensional arrays does not work

Hi,

I have the following code:

1
2
3
4
5
6
7
8
9
10
11
int native_array[2][3][4];
    int cnt = 1;
    for( auto x : native_array)
    {
        // TYPE OF x is int (*)[4]
        
        for( auto y : *x)
        {
            cout << cnt++ << " " << flush;
        }
    }


The type of x is reported as int (*)[4], but it should be int (*)[3][4]. The number of elements printed to the console is 8 ( 2 X 4) but it should be 12!

Any insights?

Juan
What is reporting the "TYPE OF x is int (*)[4]"?

Have you considered using references with those loops instead of the pointers?

for(auto& x : array)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

int main()
{
    int native_array[2][3][4] {} ;
    int n = 0 ;

    for( auto& array_2d : native_array ) // type of array_2d is int (&)[3][4]
        for( auto& row : array_2d ) // type of row is int (&)[4]
            for( int& item : row ) item = n++ ;

    for( const auto& array_2d : native_array ) // type of array_2d is const int (&)[3][4]
    {
        for( const auto& row : array_2d ) // type of row is const int (&)[4]
        {
            for( int item : row ) std::cout << item << ' ' ;
            std::cout << '\n' ;
        }
        std::cout << "\n\n" ;
    }
}

http://coliru.stacked-crooked.com/a/685dd3df1ae35bc8
Hi,

I have the following reasoning which I would like to confirm:

in the code I provided above, x is the first element of native_array which is arr[0], which is an array and therefore x is an address ( &arr[0][0] ) which has type int (*)[4].

It seems to me this is correct and it would answer my original question.

Do we agree?

Thanks
Juan
Hi,

Yes using references solves all the problems.

Just curious: is my pointer arithmetic analysis of the situation correct? It seems to explain why using auto any value instead of auto by reference does not work.


Thanks,
Juan
Just curious: is my pointer arithmetic analysis of the situation correct?

Probably not. Did you try printing out the sizes of your array using the various addressing modes?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
    int native_array[2][3][4];
    int cnt = 1;

    for( auto& x : native_array)
    {
        for( auto& y : x)
        {
            for(auto& z : y)
            {
                z = cnt;
                cout << cnt++ << '\n' ;
            }
        }
    }

    cout << &native_array << ' ' << sizeof(&native_array) / sizeof(int) << endl;
    cout << &native_array[0] << ' ' << sizeof(&native_array[0]) / sizeof(int) <<  endl;
    cout << &native_array[0][0] << ' ' << sizeof(&native_array[0][0]) / sizeof(int) << endl;
    cout << &native_array[0][0][0] << ' ' << sizeof(&native_array[0][0][0]) / sizeof(int) << endl;
    cout << endl;
    cout << native_array << ' ' << sizeof(native_array) / sizeof(int) << endl;
    cout << native_array[0] << ' ' << sizeof(native_array[0]) / sizeof(int) <<  endl;
    cout << native_array[0][0] << ' ' << sizeof(native_array[0][0]) / sizeof(int) << endl;
    cout << &native_array[0][0][0] << ' ' << sizeof(&native_array[0][0][0]) / sizeof(int) << endl;


> is my pointer arithmetic analysis of the situation correct?

Yes; since x is a value, array-to-pointer decay takes place.

1
2
3
4
for( auto x : native_array )
{
    // ...
}

is shorthand for
1
2
3
4
5
6
7
8
9
auto&& range = native_array ;
auto begin = std::begin(range) ;
auto end = std::end(range) ;

for( ; begin != end ; ++begin )
{
    auto x = *begin ; // *begin is non-copyable, therefore array to pointer decay
    // ...
}
There is a way to find out the type of any variable using this:

1
2
template<typename T>
struct AType;


This is an undefined struct so it reports the type when we use it like so:

AType<decltype(x)> x_decl;

BTW, jlb, why are you taking the address of native_array in your sizeof() statements? This will not give you the size...

If you use the above struct to find the type of x in my original 'range for' you will find the type of x is indeed as I said (int (*)[4]) and that my pointer arithmetic analysis is correct.

Thanks

Juan
BTW, jlb, why are you taking the address of native_array in your sizeof() statements? This will not give you the size...

Because that is what you asked about:

in the code I provided above, x is the first element of native_array which is arr[0], which is an array and therefore x is an address ( &arr[0][0] ) which has type int (*)[4].




Topic archived. No new replies allowed.