Поскольку все ответы до сих пор основаны на постоянной ширине, вот (тяжелое) решение для столбцов произвольной ширины:
#define matrix_type(t) struct { size_t width; t array[]; }
#define matrix_alloc(t, w, h) malloc(offsetof(matrix_type(t), array[(w) * (h)]))
#define matrix_init(m, t, w, h) \
matrix_type(t) *m = matrix_alloc(t, w, h); \
if(!m) matrix_alloc_error(); else m->width = (w);
#define matrix_index(m, w, h) m->array[m->width * (w) + (h)]
// redefine if you want to handle malloc errors
#define matrix_alloc_error()
Просто освободите массив с помощью free
.
Конечно, вы можете добавить поле для высоты и выполнять проверку границ, среди прочего.Вы можете даже написать их как фактические функции или использовать макрос для автоматического объявления типов struct
, чтобы вам не приходилось использовать анонимный тип struct
для всего.Если вам это нужно в стеке, вы можете использовать alloca
за счет переносимости.
Если у вас постоянный размер матрицы, вы можете использовать некоторые приемы приведения для достижения «родной» 2D-индексации (через[]
оператор):
#define CAT_(x, y) x##y
#define CAT(x, y) CAT_(x, y)
#define MANGLE(x) CAT(x, _hidden_do_not_use_0xdeadbeef_)
#define matrix_init(m, t, w, h) \
t MANGLE(m)[(w) * (h)]; \
t (*m)[(w)] = (void *)MANGLE(m);
// because of the funky typing, `m[0][1]` does what you'd expect it to.
Обратите внимание, что в отличие от другого решения, это создает вторую переменную, которая, вероятно, не очень чиста, но я думаю, что я использовал довольно четкий метод искажения, поэтому он выиграл 'мешать на практике.