Variadic C函数打印多个2-D char数组
我需要在C中设置一个可变参数函数,它可以并排打印可变数量的2-D char数组。 我很难弄清楚如何使用va_arg()
初始化boards
变量。
关键问题是: boards[i] = va_arg(ap, char*[][BOARDSIZE]);
该行产生编译错误(目前, Second argument to 'va_arg' is of incomplete type 'char *[][10]'
),但基本上我确定我没有做正确的事情。 我只是不确定那是什么东西。 我尝试了几种变化无济于事。 其余的代码应该没问题。
(预先感谢您的任何帮助。)
#include #include #define BOARDSIZE 10 void showBoardVariadic(int numArgs, ...) { va_list ap; va_start(ap, numArgs); // Assign an array of 2-D char arrays. char *boards[numArgs][BOARDSIZE][BOARDSIZE]; for (int i = 0; i < numArgs; i++) boards[i] = va_arg(ap, char*[][BOARDSIZE]); // TODO: Fix this line // Print the 2-D arrays side-by-side for (int row = 0; row < BOARDSIZE; row++) { for (int i = 0; i < numArgs; i++) { for (int column = 0; column < BOARDSIZE; column++) { printf(" %c", *boards[i][row][column]); } printf("\t"); } printf("\n"); } va_end(ap); } int main() { char *playerBoard[BOARDSIZE][BOARDSIZE]; char *opponentBoard[BOARDSIZE][BOARDSIZE]; // Initialize playerBoard and opponentBoard to all tildes. for (int row = 0; row < BOARDSIZE; row++) { for (int column = 0; column < BOARDSIZE; column++) { playerBoard[row][column] = "~"; opponentBoard[row][column] = "~"; } } showBoardVariadic(2, playerBoard, opponentBoard); return 0; }
实际上,我得出了像Eric一样的结论,除了我甚至没有考虑仅通过typedef
来解决多维数组问题。
出于好奇,我试图写下OP的工作版本。 当我最终得到一个我想要呈现我的代码(除了Eric Postpischils答案)。
所以,经过一些摆弄,我得到了这个工作版本testVarArgMDimArray.c
:
#include #include #define BOARDSIZE 10 #define NCOLS BOARDSIZE #define NROWS BOARDSIZE typedef char Board[NROWS][NCOLS]; typedef char (*PBoard)[NCOLS]; void showBoardVariadic(int nArgs, ...) { va_list ap; va_start(ap, nArgs); /* Attention! VLAs are an optional feature of C11. */ PBoard boards[nArgs]; for (int i = 0; i < nArgs; ++i) { boards[i] = va_arg(ap, PBoard); } /* print the 2D arrays side-by-side */ for (int row = 0; row < NROWS; ++row) { for (int i = 0; i < nArgs; ++i) { if (i) putchar('\t'); for (int col = 0; col < NCOLS; ++col) { printf(" %c", boards[i][row][col]); } } putchar('\n'); } va_end(ap); } int main() { Board playerBoard; Board opponentBoard; /* initialize boards */ for (int row = 0; row < NROWS; ++row) { #ifdef CHECK /* for checking */ /* insert some pattern in col 0 for checking */ playerBoard[row][0] = 'a' + row; opponentBoard[row][0] = 'A' + row; for (int col = 1; col < NCOLS; ++col) { playerBoard[row][col] = opponentBoard[row][col] = '~'; } #else /* productive code */ for (int col = 0; col < NCOlS; ++col) { playerBoard[row][col] = opponentBoard[row][col] = '~'; } #endif /* 1 */ } showBoardVariadic(2, playerBoard, opponentBoard); /* done */ return 0; }
在我开始工作之前,我尝试在VS2013中解决了一些问题。 太难过 - VS2013不支持VLA 。 因此,我必须记住它,但我得到它运行。
正如我在其中一条评论中所建议的那样,我选择char
作为board元素而不是char*
。 我也可以为char*
解决它,但我觉得char*
可能是OP中的“意外”选择。
按照Eric的想法,我为2D板arrays做了一个类型:
typedef char Board[NROWS][NCOLS];
更重要的可能是第二个:
typedef char (*PBoard)[NCOLS];
请记住,函数参数中的数组始终编译为指针。 C从不将数组作为参数传递。 因此,如果我们调用一个类型为Board
的参数的函数,我们将收到一个PBoard
类型的参数。
请注意*PBoard
周围的括号 - 这表示PBoard
是指向数组的指针。 如果你删除它们,你会得到一个指针数组 - 差异很大而不是预期的。
掌握了这一点后, showBoardVariadic()
东西变得相当容易。
电路板arrays声明为:
PBoard boards[nArgs];
使用va_arg
的任务很简单:
boards[i] = va_arg(ap, PBoard);
访问董事会的原因很简单:
printf(" %c", boards[i][row][col]);
这可能是令人惊讶的,但在这种情况下,指向数组的指针就像一个数组数组。 它只是一个不同的类型。 (例如,你不应该在PBoard
使用sizeof
,因为在这种情况下,不同的类型会生效。)
由于每个电路板元素在这种开发状态中包含相同的内容,我担心电路板索引中的问题是否会被忽视。 因此,我实现了另一种初始化,其中列的每个第一个元素都获得另一个字符:对于playerBoard
'a' + row
,对于opponentBoard
'A' + row
。 通过定义宏CHECK
激活此测试分配。 在我的测试环节中,我用-D CHECK
编译一次没有。
顺便说一句。 如果你想知道为什么我介绍了NROWS
和NCOLS
:在写这个答案的时候,我意识到如果我偶然在某个地方翻转行和列,我会注意到它们在OP中具有相同的大小。 因此,我将事物分开并用NROWS
≠ NCOLS
进行测试。 Phew - 它仍然正常工作。
最后但并非最不重要的是,我在Cygwin中的示例会话(因为我在Windows 10上):
$ gcc --version gcc (GCC) 6.4.0 $ gcc -std=c11 -D CHECK -o testVarArgMDimArray testVarArgMDimArray.c $ ./testVarArgMDimArray a ~ ~ ~ ~ ~ ~ ~ ~ ~ A ~ ~ ~ ~ ~ ~ ~ ~ ~ b ~ ~ ~ ~ ~ ~ ~ ~ ~ B ~ ~ ~ ~ ~ ~ ~ ~ ~ c ~ ~ ~ ~ ~ ~ ~ ~ ~ C ~ ~ ~ ~ ~ ~ ~ ~ ~ d ~ ~ ~ ~ ~ ~ ~ ~ ~ D ~ ~ ~ ~ ~ ~ ~ ~ ~ e ~ ~ ~ ~ ~ ~ ~ ~ ~ E ~ ~ ~ ~ ~ ~ ~ ~ ~ f ~ ~ ~ ~ ~ ~ ~ ~ ~ F ~ ~ ~ ~ ~ ~ ~ ~ ~ g ~ ~ ~ ~ ~ ~ ~ ~ ~ G ~ ~ ~ ~ ~ ~ ~ ~ ~ h ~ ~ ~ ~ ~ ~ ~ ~ ~ H ~ ~ ~ ~ ~ ~ ~ ~ ~ i ~ ~ ~ ~ ~ ~ ~ ~ ~ I ~ ~ ~ ~ ~ ~ ~ ~ ~ j ~ ~ ~ ~ ~ ~ ~ ~ ~ J ~ ~ ~ ~ ~ ~ ~ ~ ~ $ gcc -std=c11 -o testVarArgMDimArray testVarArgMDimArray.c $ ./testVarArgMDimArray ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ $
typedef
- 非常聪明的Eric ...
va_arg
的C规范要求“参数类型应该是指定的类型名称,以便只需通过将*固定到类型就可以获得指向具有指定类型的对象的指针的类型 。”字符串char*[][BOARDSIZE]
不满足于此。 您应该使用typedef
为该类型指定名称。
此外,在函数声明的参数列表中, char*[][BOARDSIZE]
自动调整为char*(*}[BOARDSIZE]
。在va_arg
(或typedef
)中,它不是。您应该使用调整后的表单。
因此,您应该为类型定义一个名称,该类型是指向char
的BOARDSIZE
指针数组的指针:
typedef char *(*MyType)[BOARDSIZE];
您应该将boards
更改为这些arrays而不是arrays数组:
MyType boards[numArgs];
你应该改变va_arg
来使用新类型:
boards[i] = va_arg(ap, MyType);
另请注意,您将电路板的每个元素都设置为字符串“〜”。 这会将它们全部设置为指向字符串文字,这可能不是您想要的。 您不能修改此字符串文字中的字符,因此更改电路板包含的内容的唯一方法是将它们更改为指向不同的字符串。
如果每个board元素都是单个字符,则应使用char
而不是char *
。 如果它们将是固定的或小数字的多个字符,您可能需要一个char
数组而不是指向char
的指针。 如果它们将是相当多的多个字符,您可能希望使用char *
但为每个board元素分配空间。