由于到目前为止所有答案都依赖于恒定宽度,因此这里是任意宽度列的(重量级)解决方案:
#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.
请注意,与其他解决方案不同,这会创建第二个变量,这可能不是很干净,但我认为我使用了一种非常清晰的修饰方法,因此在实践中不会妨碍它。