由于目前为止所有的答案都依赖于固定宽度,因此这里提供一种适用于任意宽度列的(笨重的)解决方案:
#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)]
#define matrix_alloc_error()
使用free
释放数组即可。
当然,您也可以添加高度字段,并进行边界检查等其他操作。您甚至可以将它们编写为实际函数,或者使用宏自动声明struct
类型,这样您就不必为每个东西都使用匿名struct
类型。如果您需要将其放在堆栈上,则可以使用alloca
,但代价是可移植性。
如果您有恒定的矩阵大小,可以使用一些强制转换技巧来实现“本地”二维索引(通过[]
运算符):
#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);
请注意,与其他解决方案不同的是,这个解决方案创建了第二个变量,可能不太干净,但我认为我使用了一种相当清晰的混淆方法,因此在实践中不会妨碍。