Fonction C variadique imprimant plusieurs tableaux de caractères 2D

Je dois configurer une fonction variadic en C qui imprime côte à côte un nombre variable de tableaux de caractères 2D. J’ai du mal à comprendre comment initialiser la variable boards avec va_arg() .

La ligne problématique principale est la suivante: boards[i] = va_arg(ap, char*[][BOARDSIZE]); La ligne produit une erreur de compilation (actuellement, le Second argument to 'va_arg' is of incomplete type 'char *[][10]' ), mais je suis sûr que je ne fais pas quelque chose de bien. Je ne suis pas sûr de savoir ce que c’est. J’ai essayé plusieurs variantes en vain. Le rest du code devrait être correct cependant.

(Merci d’avance pour toute aide.)

 #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; } 

En fait, je suis arrivé à la même conclusion que Eric, sauf que je n’avais même pas envisagé de résoudre les problèmes liés aux tableaux multidimensionnels par simple typedef .

Par curiosité, j’ai essayé de rédiger une version fonctionnelle de l’OP. Comme j’en ai enfin un, je veux présenter mon code (en plus de la réponse d’ Eric Postpischils ).

Ainsi, après quelques manipulations, j’ai obtenu cette version de travail 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; } 

Avant que je ne travaille, il y avait des problèmes que j'ai essayé de résoudre dans VS2013. Trop sortingste - VS2013 ne prend pas en charge les VLA . Par conséquent, je devais le faire à l’esprit mais je le faisais fonctionner.

Comme déjà recommandé dans l'un de mes commentaires, j'ai choisi char tant qu'élément du tableau au lieu de char* . J'aurais pu résoudre le problème pour char* également, mais j'estime que ce caractère aurait pu être un choix "accidentel" dans le PO.

Suivant l’idée d’Eric, j’ai créé un type pour le tableau de tableaux 2D:

 typedef char Board[NROWS][NCOLS]; 

Le plus important est probablement le second:

 typedef char (*PBoard)[NCOLS]; 

Rappelez-vous que les tableaux dans les parameters de fonction sont toujours compilés en tant que pointeurs. C ne passe jamais les tableaux comme arguments. Par conséquent, si nous appelons une fonction avec un argument de type Board nous recevrons un argument de type PBoard .

Veuillez noter les parenthèses autour de *PBoard - cela PBoard que PBoard est un pointeur sur array. Si vous les supprimez, vous obtenez un tableau de pointeurs - une grande différence et non ce qui est prévu.

Ceci étant maîsortingsé, les choses dans showBoardVariadic() deviennent plutôt faciles.

Le tableau de cartes est déclaré comme:

 PBoard boards[nArgs]; 

L'affectation avec va_arg est simplement:

 boards[i] = va_arg(ap, PBoard); 

L'access aux tableaux est simplement:

 printf(" %c", boards[i][row][col]); 

Cela peut paraître surprenant, mais dans ce cas, le pointeur sur tableau se comporte comme un tableau de tableaux. Il a juste un type différent. (Par exemple, vous ne devriez pas utiliser sizeof avec PBoard car dans ce cas, les différents types prendraient effet.)

Étant donné que chaque élément du conseil d'administration contient le même contenu dans cet état de développement, je craignais que les problèmes liés à l'indexation du conseil ne passent pas inaperçus. J'ai donc implémenté une initialisation alternative dans laquelle chaque premier élément de la colonne reçoit un autre caractère: pour playerBoard 'a' + row , pour l' opponentBoard 'A' + row . Cette affectation de test est activée en définissant la macro CHECK . Dans ma session de test, j'ai compilé une fois avec -D CHECK une fois sans.

Btw. si vous vous demandez pourquoi j'ai présenté NROWS et NCOLS : En écrivant cette réponse, j'ai réalisé que je ne le remarquerais pas si je retournais accidentellement des lignes et des colonnes quelque part car elles ont la même taille dans OP. Ainsi, j'ai séparé les choses et testé avec NROWSNCOLS . Ouf - cela fonctionnait toujours correctement.

Enfin, mon exemple de session sous Cygwin (comme je suis sous 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 - très intelligent Eric ...

La spécification C de va_arg requirejs que «Le type de paramètre soit un nom de type spécifié de sorte que le type d’un pointeur sur un object ayant le type spécifié puisse être obtenu simplement en postfixant un * dans le type .» La chaîne char*[][BOARDSIZE] ne satisfait pas cela. Vous devez utiliser un typedef pour donner un nom au type.

De plus, dans la liste de parameters d’une déclaration de fonction, char*[][BOARDSIZE] est automatiquement ajusté à char*(*}[BOARDSIZE] . Dans un va_arg (ou typedef ), ce n’est pas le cas. Vous devez utiliser le formulaire ajusté.

Donc, vous devriez définir un nom pour un type qui est un pointeur sur un tableau de pointeurs BOARDSIZE vers char :

 typedef char *(*MyType)[BOARDSIZE]; 

Vous devriez changer les boards pour en faire un tableau plutôt que des tableaux:

 MyType boards[numArgs]; 

et vous devriez changer va_arg pour utiliser le nouveau type:

 boards[i] = va_arg(ap, MyType); 

Notez également que vous définissez chaque élément des planches avec la chaîne “~”. Cela les configure tous pour qu’ils pointent vers un littéral de chaîne, ce qui n’est probablement pas ce que vous voulez. Vous n’êtes pas autorisé à modifier les caractères dans ce littéral de chaîne. Le seul moyen de modifier le contenu des forums est donc de les modifier pour qu’ils pointent sur des chaînes différentes.

Si chaque élément du tableau doit comporter un seul caractère, vous devez utiliser char au lieu de char * . S’il doit s’agir de plusieurs caractères fixes ou d’un petit nombre, vous pouvez utiliser un tableau de caractères plutôt qu’un pointeur sur caractères. S’il doit y avoir un nombre considérable de caractères multiples, vous pouvez utiliser char * mais allouer de l’espace pour chaque élément du tableau.