Динамические непрерывные трехмерные массивы в C - PullRequest
1 голос
/ 25 октября 2010

Я пытаюсь реализовать динамически распределенные непрерывные трехмерные массивы в коде на языке Си.Массивы должны быть смежными, потому что я полагаюсь на вывод netCDF массивов.Теперь я адаптировал решение, опубликованное здесь Stack OverFlow Solution .Это прекрасно работает для динамического выделения массивов и их индексации ... однако, когда netCDF выводит их, возникает смещение, которое масштабируется как 2-й размер индекса (jcount).Вот модифицированная функция:

void*** newarray(int icount, int jcount, int kcount, int type_size)
{
  int i,j,k;
  void*** iret = (void***)malloc(icount*sizeof(void***)+icount*jcount*sizeof(void**)+icount*jcount*kcount*type_size);
  void** jret = (void**)(iret+icount);
  char* kret = (char*)(jret+icount*jcount);
  for(i=0;i<icount;i++)
  {
    iret[i] = &jret[i*jcount];
  }
  for(i=0;i<icount;i++)
  {
    for(j=0;j<jcount;j++)
    {
      jret[i*jcount+j] = &kret[i*jcount*kcount*type_size+j*kcount*type_size];
    }
  }
  return iret;
}

Если я правильно понимаю эту функцию, iret выделено место для 3D-указателей, составляющих iret (первый индекс), для 2D-указателей, составляющих jret (2-й индекс) и пространство дляфактические значения, составляющие крет.2D указатель джрета затем связывается с секцией 2D массива iret.Затем то же самое делается для крет.Затем каждый адрес iret указывает на первое значение каждого раздела jret.Затем каждый адрес jret указывает на первый адрес kret.

Для записи все работало нормально с определенными препроцессором значениями для моих массивов.Кроме того, если я использую некоторые операторы printf в коде для проверки числовых значений массивов, все они, по-видимому, правильно индексируют и код выполняется правильно, это просто вывод, который, по-видимому, является результатом несмежного хранения в памяти массивов.

У меня есть структура вида:

typedef struct
{
  double ***test;
} STRUCT_TYPE;

, которую я затем выделяю, используя

mhd    = (STRUCT_TYPE *)  malloc(sizeof(STRUCT_TYPE));
mhd.test = (double***) newarray(101,7,101,sizeof(double));

Это может быть проблема с netCDF ... но я быпросто хочу знать, что моя процедура распределения не проблема.

Ответы [ 2 ]

1 голос
/ 26 октября 2010

Это на самом деле ответ на вопрос в ответе Лазера:

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

Может быть, кто-то может очистить этот для меня?

Существует очень фундаментальное различие в C между

double arr[A][B][C];

и

double ***ptr;

Хотя оба могут быть проиндексированы с помощью x[i][j][k], полученный машинный код сильно отличается.

double arr[A][B][C] представляет собой массив массивов AB массивов C удваивается.При индексации этого в коде как arr[i][j][k] компилятор преобразует это в смещение ((i*B + j)*C + k)*sizeof(double) байтов от начала arr.Здесь нет промежуточных указателей, но компилятору должны быть известны размеры B и C.

'double *** ptr' - указатель на (начало массива) указателей на (начало массива) указателей на (начало массива) double.При индексации этого кода в коде ptr[i][j][k] компилятору ничего не остается, кроме как выполнять каждую операцию индексации отдельно и следовать всем промежуточным указателям.В результате получается код, подобный

temp1 = ptr[i];
temp2 = temp1[j];
result = temp2[k];

Функция newarray выделяет все эти массивы компонентов из одного блока памяти, но это не требуется языком, и компилятор не обладает знаниямичто это происходит, поэтому он должен рассматривать все массивы компонентов как полностью независимые друг от друга.

0 голосов
/ 25 октября 2010

Ну, я нашел исправление ... хотя это скорее соглашение. Когда я изначально проектировал свой код, я просто использовал директиву препроцессора для объявления размеров моего массива. Затем я просто объявил каждый массив внутри структуры. Чтобы сэкономить память, я просто передал указатель на структуры своим подфункциям. Это означало, что если я собирался ссылаться на элемент вне подпрограммы main (), я использовал что-то вроде:

grid->x;

Теперь и я ссылаюсь на каждый элемент x как

grid->x[i][j][k];

Конечно, когда функции netCDF требовался указатель на переменную, которую она собиралась сохранить, я просто передавал ее

grid->x

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

&grid->x[0][0][0]

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

Может быть, кто-нибудь может прояснить это для меня?

...