在没有VLA的情况下传递可变大小的多维数组

(这是对这个问题的跟进。)

我试图理解将多维数组传递给C中的函数的“最佳实践”(或实际上是任何实践)。当然这取决于应用程序,所以让我们考虑编写一个函数来打印一个可变大小的二维数组。 特别是,我对如何在下面的代码中编写函数printArry(_____)感兴趣。

上面引用的问题中的答案使用C的可变长度数组(VLA)特性。 这些特征在C98标准中不存在 ,并且在C11标准中是可选的(它们似乎也不在C ++ 11中编译)。

如何在不使用VLAfunction的情况下回答这个问题? 传递一个二维数组似乎是一个相当基本的任务,所以我无法想象没有一个合理的方法。

 void printArry(_____){ /* what goes here? */ } int main(void){ int a1=5; int b1=6; int a2=7; int b2=8; int arry1[a1][b1]; int arry2[a2][b2]; /* set values in arrays */ printArry(arry1, a1, b1); printArry(arry2, a2, b2); return 0; } 

这个问题目前存在问题:

上面引用的问题中的答案使用C的可变长度数组(VLA)特征。这些特征在C98标准中不存在,并且在C11标准中是可选的。

C99(ISO / IEC 9899:1990)之前的C标准是C89(ANSI)或C90(ISO) – function相同的标准。 有C ++ 98(ISO / IEC 14882:1998),但这是一种完全不同的语言。

 int main(void) { int a1=5; int b1=6; int a2=7; int b2=8; int arry1[a1][b1]; int arry2[a2][b2]; 

此示例代码使用VLA; 它不会在严格的C90规则下编译。


如果您受限于1999年之前的C标准,那么您将被限制使用与此类似的代码。 显然,您可以通过读取文件中的数据或其他任何您想要的数据来初始化数组; 使用直接初始化器是可能的,因为arrays不再是VLA。

 #include  void printArry(int d1, int d2, int *data); int main(void) { enum { a1 = 5, b1 = 6, a2 = 7, b2 = 8 }; int arry1[a1][b1] = { { 9, 8, 7, 6, 5, 4 }, { 2, 3, 4, 3, 2, 1 }, { -9, -8, -7, -6, -5, -4 }, { 39, 38, 37, 36, 35, 34 }, { 99, 98, 97, 96, 95, 94 }, }; int arry2[a2][b2] = { { 198, 158, 165, 136, 198, 127, 119, 103, }, { 146, 123, 123, 108, 168, 142, 119, 115, }, { 160, 141, 168, 193, 152, 152, 147, 137, }, { 144, 132, 187, 156, 188, 191, 196, 144, }, { 197, 164, 108, 119, 196, 171, 185, 133, }, { 107, 133, 184, 191, 166, 105, 145, 175, }, { 199, 115, 197, 160, 114, 173, 176, 184, }, }; printArry(a1, b1, &arry1[0][0]); printArry(a2, b2, &arry2[0][0]); return 0; } void printArry(int d1, int d2, int *data) { int i, j; for (i = 0; i < d1; i++) { for (j = 0; j < d2; j++) printf(" %4d", data[i * d2 + j]); putchar('\n'); } } 

printArry()函数本质上是做编译器为你做的索引(下标)计算 - 但它不能,因为它无法处理C99 VLA。

第一个数据数据是手工制作的,以便发现问题(例如d1标计算中使用d1而不是d2 )。 第二个数据arrays只是介于100和199之间的56个随机值。

样本输出:

  9 8 7 6 5 4 2 3 4 3 2 1 -9 -8 -7 -6 -5 -4 39 38 37 36 35 34 99 98 97 96 95 94 198 158 165 136 198 127 119 103 146 123 123 108 168 142 119 115 160 141 168 193 152 152 147 137 144 132 187 156 188 191 196 144 197 164 108 119 196 171 185 133 107 133 184 191 166 105 145 175 199 115 197 160 114 173 176 184 

您不需要VLA来传递VLA作为参数。 实际上你必须知道数组和函数既不能传递给函数也不能从函数返回(除非你使用结构hack,但在我们的例子中这不起作用)。

但是,您可以使用VM类型将指针传递给您的arrays。 像这样的东西:

 void printArry(size_t a1, size_t b1, int (*parry)[a1][b1]){ /* accessing array 'array' by '*parry' */ } 

在声明定义数组维度的参数后,必须声明指向VLA数组参数的指针,原因显而易见(’a1’和’b1’必须在使用时定义)。

使用此函数的代码如下所示:

 int main(int argc, char** argv){ size_t a1=5; size_t b1=6; size_t a2=7; size_t b2=8; int arry1[a1][b1]; int arry2[a2][b2]; /* set values in arrays */ printArry(a1, b1, &arry1); printArry(a2, b2, &arry2); } 

我们不能首先使用结构hack,因为结构不能有VLA成员,其次因为即使它们可以在传递参数时也无法指定它们的长度(成员类型必须在声明,我们不能在函数声明中声明结构)。

确认 – 即使普通(非VM)arrays也必须使用此版本的’printArry’(假设它们的尺寸大小正确传递给函数)。 至少这是C11标准在其示例中所说的内容。

所有指向具有相同尺寸大小的数组的指针都可以相互分配(无论它们是否为VM),而无需调用UB。

以下是最新C11标准的示例,其来源于:

示例3以下声明演示了可变修改类型的兼容性规则。

 extern int n; extern int m; void fcompat(void) { int a[n][6][m]; int (*p)[4][n+1]; int c[n][n][6][m]; int (*r)[n][n][n+1]; p = a; // invalid: not compatible because 4 != 6 r = c; // compatible, but defined behavior only if // n == 6 and m == n+1 } 

6.7.6.2美元。

这意味着您可以调用此函数,例如:

 int main(int argc, char **argv) { int arry[10][23]; printArry(sizeof(arry) / sizeof(arry[0]), sizeof(arry[0]) / sizeof(arry[0][0]), &arry); } 

另一方面,您也可以使用指向它的第一个元素的简单指针访问您的数组:

 void printArry(size_t a1, size_t b1, int *parryFirstElement){ for(size_t i = 0; i < a1; ++i) for(size_t y = 0; y < b1; ++y) parryFirstElement[i * b1 + y]; //your array [i][y] element } 

调用此函数可以像以前一样完成(因为'C'中的IIRC指针不需要被转换)。

我在更好地使用'size_t'的时候替换'int'。 虽然如果你的目标是一些旧标准,你可以将它们反转回'int'。

我可能错了。 我现在困了。 如果我错了 - 那就糟糕了。

似乎存在对标准和VLA的误解:C99和所有后续C标准都包含VLA,而编译器(例如gcc支持它(使用-std=c99-std=C11等标志)。

什么是行不通的,是任何标准的C ++ 。 VLA根本不是该语言的一个特征,C在这方面比C ++更强大。

因此,如果您想使用VLA,只需确保使用真正的C编译器( gcc )进行编译,而不是使用C ++编译器( g++ )进行编译。 如果你这样做,他们应该像魅力一样工作。


Afaik,有一个关于C ++ 17的提议,它表示它希望在语言中添加VLA。 但是,该提案中的VLAfunction受到严重限制。 直到我眼中完全无法使用的程度。 在这方面,C99仍然比C ++ 17强大得多。