5

If you can use pointers to iterate through an array like this:

for (int *iter = arr; iter != std::end(arr); ++iter) {
    // code
}

How do you iterate through a multidimensional array with pointers (without using auto)?

EDIT: I am assuming this is an int[][] such as {{3, 6, 8}, {2, 9, 3}, {4, 8, 2}}

1
  • 1
    It might be the right time to who how your arr was actually declared. Commented Sep 20, 2013 at 9:39

6 Answers 6

7

If you declared array as arr[][], and yes you can because they are stored sequentially in memory. You can do:

for(int * iter = &arr[0][0]; iter != &arr[0][0] + col * row; iter++)
//...
Sign up to request clarification or add additional context in comments.

1 Comment

Is there anyway of finding &arr[0][0] + col * row without knowing the array size (std::end(arr[2]) worked, but you require the number of arrays)
2

For example:

constexpr size_t rowCnt = 3, colCnt = 4;

int ia[rowCnt][colCnt] = { // three elements; each element is an array of size 4
     {0, 1, 2, 3}, // initializers for the row indexed by 0
     {4, 5, 6, 7}, // initializers for the row indexed by 1
     {8, 9, 10, 11} // initializers for the row indexed by 2
    };

Not using a type alias for the type of the loop control variables:

// p points to the first array in ia
for (int (*p)[colCnt] = ia; p != ia + rowCnt; ++p) {
    // q points to the first element of an array of four ints; that is, q points to an int
    for (int *q = *p; q != *p + colCnt; ++q)
        cout << *q << " ";
    cout << endl;
}

or easier using auto:

for (auto p = ia; p != ia + rowCnt; ++p) {
    // q points to the first element of an array of four ints; that is, q points to an int
    for (auto q = *p; q != *p + colCnt; ++q)
        cout << *q << " ";
    cout << endl;
}

Comments

1

How about trying like this:-

const int* d = data;
for ( int i = 0; i < width; ++i )
    for ( int j = 0; j < height; ++j )
        for ( int k = 0; k < depth; ++k )
            sum += *d++;

Check this tutorial

16 Comments

That's not strictly speaking a multi-dimensional array.
That's a hack that works only if the memory allocated for that multidimensional array is continuous. If you were to have an int ** array, you would have to allocate a block of multiple int * (one chunk of memory), then N allocations for each of those int * addresses (N chunks of memory).
It should work however for statically allocated multidimensional arrays like an int a[100][100]; declaration.
@Sebastian-LaurenţiuPlesciuc "That's a hack that works only if the memory allocated for that multidimensional array is continuous." - That is definitely not a hack, since the memory of a multidimensional array is always contiguous.
@Sebastian-LaurenţiuPlesciuc "If you were to have an int** array, you would have to allocate a block of multiple int* (one chunk of memory), then N allocations for each of those int* addresses (N chunks of memory)." - That would be an array of pointers pointing to dynamically allocated arrays, which has nothing to do with multidimensional arrays at all.
|
0

Improving texasbruce's answer(couldn't comment sorry) with sizeof trick, assuming array is statically allocated(dimensions are known at compile-time) for(int * iter = &arr[0][0]; iter != &arr[0][0] + sizeof(arr)/sizeof(int); iter++) or iter != (int*)((void*)&arr[0][0] + sizeof(arr)) if you're (void*) fan and hate any compile-time divisions

So you don't have to bother with array dimensions :)

Comments

-1

Probably something like this

   for (int **iter = arr; iter != std::end(arr); ++iter) {
        for (int *iter2 = *iter; iter2 != std::end(*arr); ++iter2) {
        // code
        }
    }

11 Comments

This seems to produce the error cannot convert type int (*)[2] to** int
Yeah i didn't test it. Just removed one obvious bug. Try it now.
Still the same error, since obviously a multidimensional array cannot be converted into a multi-pointer. Can it be you're actually thinking about an array of pointers instead of a real multidimensional array?
Yes, I was assuming that. You never said how you declared the array.
"Multi pointer" is the common way to allocate multi dimensional arrays as it can be done dynamically. Please edit your question to include the array declaration / allocation this so there is no confusion on this.
|
-1

Assuming you are simply talking about statically declared multi-dimensional arrays:

const int ROWS = 10;
const int COLS = 20;
const int DEPTH = 30;
int array[ROWS][COLS][DEPTH]; // statically allocated array
int i = 0;
for (int row = 0; row < ROWS; ++row)
{
    for (int col = 0; col < COLS; ++col)
    {
        for (int depth = 0; depth < DEPTH; ++depth)
        {
            *(*(*(array + row) + col) + depth) = i++; // do whatever with it
            // is equivalent to array[row][col][depth] = i++;
        }
    }
} 

If you need more levels, you just keep adding levels of pointer indirection.

Alternatively:

const int ROWS = 5;
const int COLS = 6;
const int DEPTH = 3;
int array[ROWS][COLS][DEPTH]; // statically allocated array
int* p = &array[0][0][0];
int c = 0;
for (int i = 0; i < ROWS * COLS * DEPTH; ++i, p++)
{
    *p = c++;
}

Since a statically declared array is going to be contiguous in memory, with the first element (array[0][0][0]) starting at the base address (&array), this works.

Declaring a multi-dimensional array dynamically is going to be a pointer to an array of pointers to (etc) to pointers to an array of object_type. You can simplify that by using std::vector or std::array (if you know the size at compile time).

Not that these use pointers to iterate (at least not directly), but

Vector/Array

std::vector<std::vector<std::vector<int> > > array;
// or
//std::array<std::array<std::array<int, DEPTH>, COLS>, ROWS> array; // with some slight modifications
// fill in the vectors/arrays however you want

std::for_each(array.begin(), array.end(), [](const std::vector<std::vector<int> >& v)
{
    std::for_each(v.begin(), v.end(), [](const std::vector<int>& a)
    {
        std::for_each(a.begin(), a.end(), [](int i)
        {
            std::cout << i << endl;
        });
    });
});

10 Comments

Uh, how do you index an array with a int***? And by the way, your array isn't an array at all, it's a pointer of pointers to pointers.
And exactly what you describe is not a multidiemsional array. It's an array of pointers pointing to dynamically allocated arrays (and so on). There is a definite difference because exactly this statement "If you declare it int array[10][20][30], you still (effectively) end up with an int***" - Is plain wrong. Try int array[10][20][30]; int ***p = array; and see what happens. That's the whole point of the OP's question in the end.
And even apart from that your code doesn't make any sense for your described dynamic array of pointers to dynamic arrays either. Look at the part int*** i= ... [...] array[i] and tell me how that should even compile. What you probably meant was *i instead of array[i] (and likewise for the other iterators).
"but for the most part, a statically declared multi-dimensional array will behave the same as a dynamically declared pointer to pointer to array." - Just not for the part relevant to the question. Seriously, just try int*** i = std::begin(array) or int*** i = array or whatever and prepare for a nasty surprise.
I saw that you fixed part of your loops, but still seem to be reluctant to try it out. How should std::end even find the end of a mere pointer. It is one of the few functions that really need an actual array and not just an array decayed to a pointer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.