Как преобразовать массив в 2d-матрицу без выделения дополнительной памяти в C? - PullRequest
0 голосов
/ 27 июня 2019

Это следующий вопрос: C - преобразование массива элементов в 2-мерную матрицу

Чтобы сделать преобразование, я получил метод:

int (* M)[b] = (int (*) [b])array

, где M[a][b] и array[a * b].

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

Пример (обновление):

/* conversion.c */

int main(void) {
    int flag, array[30], b = 3;

    if (flag)
        goto done;

    int (* M)[b] = (int (*)[b]) array;

done:
    return 0;
}

компиляция с gcc-9:

conversion.c: In function 'main':
conversion.c:5:3: error: jump into scope of identifier with variably modified type
    5 |   goto done;
      |   ^~~~
conversion.c:9:1: note: label 'done' defined here
    9 | done:
      | ^~~~
conversion.c:7:9: note: 'M' declared here
    7 |  int (* M)[b] = (int (*)[b]) array;
      |         ^
conversion.c:5:3: error: jump into scope of identifier with variably modified type
    5 |   goto done;
      |   ^~~~
conversion.c:9:1: note: label 'done' defined here
    9 | done:
      | ^~~~
conversion.c:7:9: note: '({anonymous})' declared here
    7 |  int (* M)[b] = (int (*)[b]) array;
      |         ^

обновление: error: jump into scope of identifier with variably говорит о том, что оператор goto пытается перепрыгнуть (во время компиляции) неизвестный размер памяти в стеке, что означает, что в стеке выделяется память из-за приведенного выше преобразования.

1 Ответ

1 голос
/ 27 июня 2019

на самом деле в стеке находится массив размера b

Ничего подобного не происходит.Вы пытаетесь объявить указатель на массив, а не на массив.

Самый первый абзац раздела goto стандарта запрещает то, что вы пытаетесь сделать.

6.8.6.1 [Оператор goto] / 1 Оператор goto не должен переходить из области видимости идентификатора, имеющего переменно измененный тип, в область видимости этого идентификатора.

Не имеет значения,объем памяти, занимаемый объектом, обозначенным рассматриваемым идентификатором, является переменным или постоянным.Достаточно того, что его тип является производным от типа VLA, например, если это указатель на него.

Для этого вам не нужно указывать goto или многое другое.

int main(void) {
    int flag = 0, array[30], b = 3;

    if (!flag) {
        int (*M)[b] = (int (*)[b]) array;
        // note that dereferencing M here is undefined behaviour
        (void)M;
    }
    return 0;
}

Живая демоверсия

...