2012-01-07 3 views
4

Т.И. имеют следующий код:альтернатива многомерный массив в с

#define FIRST_COUNT 100 
#define X_COUNT 250 
#define Y_COUNT 310 
#define z_COUNT 40 

struct s_tsp { 

    short abc[FIRST_COUNT][X_COUNT][Y_COUNT][Z_COUNT]; 
}; 

struct s_tsp xyz; 

Мне нужно запустить через данные, как это:

for (int i = 0; i < FIRST_COUNT; ++i) 
    for (int j = 0; j < X_COUNT; ++j) 
      for (int k = 0; k < Y_COUNT; ++k) 
       for (int n = 0; n < Z_COUNT; ++n) 
         doSomething(xyz, i, j, k, n); 

Я пытался придумать более элегантный, менее разумный подход к мозгу. (Я знаю, что этот многомерный массив неэффективен с точки зрения использования процессора, но в данном случае это не имеет значения.) Есть ли лучший подход к тому, как я здесь структурировал?

+1

Что вы пытаетесь сделать с данными? Трудно сказать вам, что попробовать, не зная ничего о том, что вы делаете. – user1118321

ответ

5

Если вам нужен 4D-массив, то это то, что вам нужно. Можно «сгладить» его в одномерный malloc() эд «массив», однако это не совсем чиста:

abc = malloc(sizeof(short)*FIRST_COUNT*X_COUNT*Y_COUNT*Z_COUNT); 

Допуски также сложнее:

*(abc + FIRST_COUNT*X_COUNT*Y_COUNT*i + FIRST_COUNT*X_COUNT*j + FIRST_COUNT*k + n) 

Так что это, очевидно, немного боли.

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

for (int i = 0; i < FIRST_COUNT*X_COUNT*Y_COUNT*Z_COUNT; i++) { 
    doWhateverWith *(abc+i); 
} 

Очевидно, что этот метод очень некрасиво для большинства применений, и немного аккуратнее для одного тип доступа. Это также немного более консервативно для памяти и требует только одного указателя-разыменования, а не 4.

+1

Вы всегда можете просто написать небольшой модуль с функциями доступа и обернуть тип в структуре, чтобы получить чистый API. – pmr

+5

Правда. Вы даже можете сделать это с помощью макросов, если вы действительно плохой человек. – Dan

2

ПРИМЕЧАНИЕ. Намерение примеров, используемых в этом сообщении, - это просто объяснение понятий. Таким образом, примеры могут быть неполными, могут отсутствовать обработка ошибок и т. Д.

Когда дело доходит до использования многомерного массива в C, возможны два возможных способа.

Сведение массивов

В C массивы реализованы в виде непрерывного блока памяти. Эта информация может использоваться для управления значениями, хранящимися в массиве, и обеспечивает быстрый доступ к определенному местоположению массива.

Например,

int arr[10][10]; 
int *ptr = (int *)arr ; 

ptr[11] = 10; 
// this is equivalent to arr[1][0] = 10; assign a 2D array 
// and manipulate now as a single dimensional array. 

Методика использования непрерывной природы массивы известен как flattening of arrays.

Рваные Массивы

Теперь рассмотрим следующий пример.

char **list; 
list[0] = "United States of America"; 
list[1] = "India"; 
list[2] = "United Kingdom"; 
for(int i=0; i< 3 ;i++) 
    printf(" %d ",strlen(list[i])); 
// prints 24 5 14 

Этот тип реализации известен как оборванный массив и полезен в тех местах, где используются строки переменного размера. Популярный метод состоит в том, чтобы сделать dynamic-memory-allocation для каждого измерения.

ПРИМЕЧАНИЕ: Аргумент командной строки (char *argv[]) передается только как оборванный массив.

Сравнивая плоские и неровные массивы

Теперь давайте рассмотрим следующий фрагмент кода, который сравнивает flattened и ragged массивы.

/* Note: lacks error handling */ 
int flattened[30][20][10]; 
int ***ragged; 
int i,j,numElements=0,numPointers=1; 
ragged = (int ***) malloc(sizeof(int **) * 30); 
numPointers += 30; 
for(i=0; i<30; i++) { 
    ragged[i] = (int **)malloc(sizeof(int*) * 20); 
    numPointers += 20; 
    for(j=0; j<20; j++) { 
     ragged[i][j]=(int*)malloc(sizeof(int) * 10); 
     numElements += 10; 
    } 
} 

printf("Number of elements = %d",numElements); 
printf("Number of pointers = %d",numPointers); 

// it prints 
// Number of elements = 6000 
// Number of pointers = 631 

Из приведенного выше примера, в ragged массивы требуют 631-pointers, другими словами, 631 * sizeof(int *) дополнительные ячейки памяти для указывая 6000 целых чисел. В то время как для массива flattened требуется только один базовый указатель: т. Е. Имя массива достаточно, чтобы указывать на смежные ячейки памяти 6000.

Но OTOH, массивы ragged являются гибкими. В случаях, когда точное количество требуемых мест памяти неизвестно, вы не можете позволить себе распределить память для наихудшего возможного случая. Опять же, в некоторых случаях точное количество требуемого пространства памяти известно только во время выполнения. В таких ситуациях ragged массивы становятся удобными.

Роу-мажор и столбцы из основных массивов

C следующим образом row-major упорядочения для многомерных массивов. Flattening массивов можно рассматривать как эффект из-за этого аспекта в C. Значение порядка в порядке его соответствия этому естественному способу, в котором большая часть доступа осуществляется в программировании. Например, давайте рассмотрим пример для обхода N * M 2D матрицу,

for(i=0; i<N; i++) { 
    for(j=0; j<M; j++) 
     printf(“%d ”, matrix[i][j]); 
    printf("\n"); 
} 

Каждая строка в матрице доступен один за другим, меняя колонку быстро. Массив C устроен в памяти естественным образом. Напротив, рассмотрим следующий пример:

for(i=0; i<M; i++) { 
    for(j=0; j<N; j++) 
     printf(“%d ”, matrix[j][i]); 
    printf("\n"); 
} 

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

Потому что первый обращается к массиву в натуральном порядке (row-major), поэтому он быстрее, тогда как второй занимает больше времени, чтобы прыгать. Разница в производительности будет расширяться по мере увеличения количества измерений и размера элемента.

Поэтому при работе с многоразмерными массивами в C, полезно рассмотреть приведенные выше детали!

+0

Имеются значительные проблемы с некоторыми из вашего кода, включая использование неинициализированных переменных и преобразований неопределенного типа. – dreamlax

+0

@dreamlax Да, фрагмент кода является неполным. Они предназначены для объяснения идей и концепций. Как я уже упоминал, в нем отсутствует обработка ошибок, 'free()' 'ы выделенной памяти и неинициализированной памяти. –

Смежные вопросы