C99 Как привести простой указатель к многомерному массиву переменной длины?

В моих телах функций reduce() и initialize(...) я хочу работать с массивом globalArray как с трехмерным, размеры которого неизвестны до времени выполнения.

Как преобразовать указатель globalArray в массив переменной длины (указатель) и использовать его естественным образом? Я думаю, что подход typedef помогает, но я все еще потерян. Эта текущая версия компилируется и, по-видимому, работает после моей переделки. Являются ли слепки №1 и №2 настолько четкими и безопасными, насколько это возможно?

#include <stdlib.h>
#include <stdio.h>

double * globalArray; /* working from a situation where the array is global, declared elsewhere */
int M, N, P; /*array dimensions not known until runtime */

double reduce();
double reduce()
{
    /* Here I want to re-interpret the one-dimensional globalArray into
       a multi-dimensional variable-length array so that compiler takes
       care of the indexing math for me.*/
    typedef double (*arr_t)[N][P];

    const arr_t castArray = (arr_t)globalArray;  /* Cast #1 */

    double sum=0.0;
    for (int i=0; i<M; i++)
        for (int j=0; j<N; j++)
            for (int k=0; k<P; k++)
                sum += castArray[i][j][k];
    return sum;
}

void initialize(int M, int N, int P, double threedimarray[M][N][P])
{
    for (int i=0; i<M; i++)
        for (int j=0; j<N; j++)
            for (int k=0; k<P; k++)
                threedimarray[i][j][k] = (double)(i*N*P + j*P + k);
}

int main(int argc, char **argv)
{
    M = 10; N=1000; P=200;
    globalArray = malloc( M*N*P* sizeof(double) );

    typedef double (*arr_t)[N][P];
    initialize(M, N, P, (arr_t)globalArray); /* Cast #2 */

    double result = reduce();
    printf("Reduced result: %f\n", result );
    return 0;
}

https://ideone.com/5Y8Q64

Я переделываю небольшой раздел большой программы. Есть явно лучшие подходы к проектированию, чем указатели массива области действия программы. Что есть, то есть. С точки зрения самодокументирования было бы неплохо, если бы решение не отбрасывало тот факт, что мы также «знаем» размер ведущего измерения (M).

Подобные вопросы SO, относящиеся к объявлениям аргументов функций, полезны, но, я думаю, я не соединяю точки. Я решил спросить здесь, надеясь, что ответ дойдет до большего количества людей.


person NoahR    schedule 26.09.2017    source источник
comment
Вы пробовали: double castArray[M][N][P] = (double[][][])globalArray; ?   -  person VuVirt    schedule 26.09.2017
comment
Ну, теперь у меня есть: ошибка: массив имеет неполный тип элемента 'двойной []'   -  person NoahR    schedule 26.09.2017
comment
Вы можете сделать это так, но M, N и P должны быть константными: double(castArray)[2][2][2] = (double()[2][2][2 ]) глобальный массив; Но лучше обращаться к globalArray так: globalArray[i * M + j * N + k], где 0 ‹= i ‹ M; 0 ‹= j ‹ N; 0 ‹= к ‹ Р;   -  person VuVirt    schedule 26.09.2017
comment
Правильным выражением будет globalArray[i * N*P + j * P + k], но это именно то, чего я пытаюсь избежать с помощью функциональности массивов переменной длины C99.   -  person NoahR    schedule 26.09.2017


Ответы (1)


Вот одно из возможных решений для кастинга, к которому я пришел после некоторой возни.

typedef double (*arr_t)[N][P];
arr_t castArray = (arr_t)globalArray;

/* Now castArray can be accessed by multi-dimensional index notation */
castArray[i][j][k] = 3.14;

Недостатки:

1) Не документирует известную длину начального размера M.

person NoahR    schedule 26.09.2017