2015-10-23 7 views
3

Предположим, я хочу что-то сделать для каждого числа в многомерном массиве. Я обнаружил, что вы можете получить указатель на первый номер, а затем использовать добавление указателя использования. Например, следующий код выводит номер 1 через 12:Итерация по многомерным массивам

double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}}; 
double *p = &a[0][0][0]; 
for (int i = 0; i < 12; i++) 
    cout << *(p + i) << endl; 

ли unidiomatic рассматривать многомерный массив как быть плоским таким образом? Если да, то каков предпочтительный способ сделать это? Кроме того, существует ли более простой способ написать double *p = &a[0][0][0];, чтобы получить указатель на первое число в многомерном массиве (точно так же, как вы можете просто написать double *p = a; для одномерного массива)?

ответ

6

Да, многомерный массив гарантированно будет плоским. Однако, может быть, лучше всего отнестись к подобным вещам. Если вы хотите, чтобы плашмя перебрать многомерный массив, я думаю, было бы лучше, чтобы ввести вид диапазона в него:

template <typename T> 
struct Flat { 
    auto begin() { return first(arr); } 
    auto end() { 
     return begin() + sizeof(arr)/sizeof(*begin()); 
    } 

    template <typename X> X* first(X& val) { return &val; } 
    template <typename X, size_t N> auto first(X(&val)[N]) { return first(*val); } 

    T& arr; 
}; 

template <typename T> 
Flat<T> flatten(T& arr) { 
    return Flat<T>{arr}; 
} 

И просто использовать, что один:

for (double d : flatten(a)) { 
    std::cout << d << std::endl; 
} 

В противном случае, только Другой способ объявления p - это что-то вроде double *p = &***a;. Я не уверен, что если вы станете программистом на три звезды, то в вашем списке жизненных достижений.

+2

плюс один для «трехзвездочного программирования» – vsoftco

+0

Разве это не слишком сложно? – Numeri

+0

@Numeri Нет, не совсем. – Barry

1

Да, многомерный массив всегда можно рассматривать как плоский. Также, как и одномерный массив, вы можете сказать double *p = reinterpret_cast<double*>(a), что совпадает с double *p = &a[0][0][0].

Многомерный массив, если он динамически распределен, может быть не плоским. Но тогда это было бы очевидно, поскольку выделение будет сделано вами.

+0

Я попытался 'двойной * р = а;' и он говорит, 'ошибка: не удается преобразовать 'двойной (*) [3] [2]' в«двойной * 'в инициализации double * p = a; ' –

+0

жаль, что я забыл, что на C++ вам нужно указать тип указателя для соответствия. Я обновил свой ответ соответственно – jayant

+1

Спасибо, 'double * p = reinterpret_cast (a)', похоже, работает. –

3

Хотя это может быть очень полезно знать, что многомерный массив на самом деле плоская, она обычно будет unidiomatic обратиться к нему с помощью указателей и арифметики указателей, потому что он вводит больше возможностей для ошибок и труднее, чем читать идиоматическое решение, индексная нотация. Из-за этого, я рекомендовал бы использовать это:

double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}}; 

for (int i = 0; i < 2; i++) 
{ 
    for (int j = 0; j < 3; j++) 
    { 
     for (int k = 0; k < 2; k++) 
     { 
      cout << a[i][j][k] << endl; 
     } 
    } 
} 
Смежные вопросы