Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

range-based for on multi-dimensional array

My embedded system got a C++11-capable version of g++, so I've been cleaning up code from

for( uint16_t* p = array; p < (&array)[1]; ++p ) {
    *p = fill_value;
}

to

for( uint16_t& r : array ) {
    r = fill_value;
}

which is much more readable.

Is there a range-based for loop which operates over all elements of array2[m][n]?

The old version is

for( int16_t* p = array2[0]; p < (&array2)[1][0]; ++p ) {
    *p = fill_value;
}

and I don't want nested loops, unless it's guaranteed the compiler will flatten them.

(FWIW, the compiler is the GNU 4.7.4 Linaro g++ ARM cross-compiler that ships with TI Code Composer Studio 6.0.0)

like image 933
Ben Voigt Avatar asked Jun 19 '14 22:06

Ben Voigt


People also ask

What is multi-dimensional array with example?

A multi-dimensional array is an array with more than one level or dimension. For example, a 2D array, or two-dimensional array, is an array of arrays, meaning it is a matrix of rows and columns (think of a table). A 3D array adds another dimension, turning it into an array of arrays of arrays.

What is multi-dimensional array?

A multidimensional array in MATLAB® is an array with more than two dimensions. In a matrix, the two dimensions are represented by rows and columns. Each element is defined by two subscripts, the row index and the column index.

What is multi-dimensional array used for?

Multi-dimensional arrays are an extended form of one-dimensional arrays and are frequently used to store data for mathematic computations, image processing, and record management.

Can multi-dimensional arrays be indexed?

Indexing multi-dimensional arrays Multi-dimensional arrays are indexed in GAUSS the same way that matrices are indexed, using square brackets [] . Scanning above, you can see that the value of the element at the intersection of the third row and second column of x1 is 8.


4 Answers

As an example, there are various ways to print and manipulate value of a multidimensional array.

int arr[2][3] = { { 2, 3, 4 }, { 5, 6, 7} };  

First Method,

size_t count = 0 ; 

for( auto &row : arr)
    for(auto &col : row)
         col = count ++; 

Here in the first for loop we are referring to the two array. Then in the second array we have reference to the 3 elements of those subarrays separately. And we are also assigning count to col. So, it iterates over to the next element of the subarray.

Second Method,

for( auto &row : arr)
     for( auto col : row)
          cout << col << endl; 

We take reference here in the first loop because we want to avoid array to pointer conversion.

If this is done( error case: first for loop is not a reference ),

for( auto row : arr)          // program won't compile
     for( auto col : row)

Here, we have int * in row. By the time we reach the second for loop. Because row is now int * and not a list the program will not compile. You have to create a list then only we can pass that it to ranged for loop and use it for iterating over that list.

vector<int> list = { *(row+0) , *(row+1) , *(row+ 2) } ;

Now we can use the list for iteration

for ( ----- : list)
like image 60
abhimanyuaryan Avatar answered Oct 16 '22 22:10

abhimanyuaryan


for ( auto &a : array )
{
   for ( int &x : a ) x = fill_value;
}

EDIT: You can try the following

const size_t n = 2;
const size_t m = 3;

int a[n][m] = { { 1, 2, 3 }, { 4, 5, 6 } };

for ( auto &x : reinterpret_cast<int ( & )[n * m]>( a ) )  x = 10;
for ( auto x : reinterpret_cast<int ( & )[n * m]>( a ) )  std::cout << x << ' ';
std::cout << std::endl;;

The output is

10 10 10 10 10 10 

The advantage of this approach is that you can reinterpret any multidimensional array not only a two-dimensional array. For example

int a[n][m][k] = { /* some initializers */ };

for ( auto x : reinterpret_cast<int ( & )[sizeof( a ) / sizeof( ***a )]>( a ) )
{
    std::cout << x << ' ';
}
std::cout << std::endl;;
like image 37
Vlad from Moscow Avatar answered Oct 16 '22 22:10

Vlad from Moscow


Here's some code that will fill an arbitrary array (of statically known size):

#include <algorithm>
#include <iterator>
#include <type_traits>

template <typename T>
void fill_all(T & a, typename std::remove_all_extents<T>::type v);

template <typename T>
void fill_all_impl(T & a, typename std::remove_all_extents<T>::type v, std::false_type);

template <typename T>
void fill_all_impl(T & a, typename std::remove_all_extents<T>::type v, std::true_type)
{
  for (auto & x : a)
    fill_all(x, v);
}

template <typename T>
void fill_all_impl(T & a, typename std::remove_all_extents<T>::type v, std::false_type)
{
  std::fill(std::begin(a), std::end(a), v);
}

template <typename T>
void fill_all(T & a, typename std::remove_all_extents<T>::type v)
{
  fill_all_impl(a, v, std::is_array<typename std::remove_extent<T>::type>());
}

Example usage:

int a[3][4][2];
fill_all(a, 10);
like image 3
Kerrek SB Avatar answered Oct 16 '22 23:10

Kerrek SB


Combining parts of Vlad's and Praetorian's answers, I decided to use:

template<typename T, size_t N, size_t M>
auto flatten(T (&a)[M][N]) -> T (&)[M*N] { return reinterpret_cast<T (&)[M*N]>(a); }

for( int16_t& r : flatten(array2) ) {
    r = fill_value;
}
like image 1
Ben Voigt Avatar answered Oct 16 '22 23:10

Ben Voigt