Le passage d'un multidimensionnelle de longueur variable tableau à une fonction
Il ya des tonnes de questions similaires, mais encore je ne pouvais pas trouver une réponse pertinente à la fonction de la longueur variable des tableaux en C99/C11.
Comment passer multidimensionnelle de longueur variable tableau à une fonction dans C99/C11?
Par exemple:
void foo(int n, int arr[][]) //<-- error here, how to fix?
{
}
void bar(int n)
{
int arr[n][n];
foo(n, arr);
}
Compilateur (g++-4.7 -std=gnu++11
) dit:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first
Si je l'ai changer pour int *arr[]
, le compilateur se plaint encore:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’
Question suivante, comment faire pour passer par valeur et comment le transmettre par référence? Apparemment, habituellement, vous ne voulez pas l'ensemble du tableau à copier lorsque vous passez à une fonction.
Constante avec les tableaux de longueur c'est simple, depuis, que la "constante" qui implique, vous devez connaître la longueur lorsque vous déclarez la fonction:
void foo2(int n, int arr[][10]) //<-- ok
{
}
void bar2()
{
int arr[10][10];
foo2(10, arr);
}
Je sais, passage de tableaux à des fonctions comme ce n'est pas une bonne pratique, je ne l'aime pas du tout. Il est probablement mieux de le faire avec des pointeurs plat, ou des objets (comme std:vecteur) ou quelque chose d'autre. Mais encore, je suis un peu curieux de ce qui est ici, la réponse à partir d'un point de vue théorique.
- Ne pourriez-vous pas utiliser
std::vector<std::vector<int>>
et d'éviter tous ces problèmes? - Blaise ne sont pas en C++11.
- La réponse à partir d'un point de vue théorique est: "Vous ne pouvez pas". Lors du passage d'un tableau comme paramètre, vous obtenez seulement un "libre" de dimension. Les autres doivent être spécifiés comme des expressions constantes (c'est à dire, des valeurs connues au comple temps).
- un vecteur de vecteurs vous donne trop de liberté à définir votre dimension (
arr[0]
peut avoir la taille3
,arr[1]
taille5
, et ainsi de suite). Je suppose que Boost.MultiArray est le bon choix. - Je suis d'accord. Je l'envelopper dans une sorte de matrice de classe.
- La Longueur Variable des Tableaux (VLA) est une partie de C99 et a été dans GCC depuis des années. Ils sont toutefois pas pris en charge par MSVC++.
- Blaise ne sont pas standard C++ soit, ils sont donc mieux éviter.
- À mon humble avis, c'est assez sûr de dire qu'elle ne sera jamais dans MSVC. Microsoft ne semble pas être vraiment intéressés à soutenir C.
- Oui, vous avez raison, c'est C99/C11 fonctionnalité
- Voir le dernier paragraphe
Vous devez vous connecter pour publier un commentaire.
Passage de tableaux à des fonctions est un peu drôle en C et C++. Il n'y a pas rvalues de la matrice de types, de sorte que vous êtes en fait en passant un pointeur.
À l'adresse d'un tableau 2D (un vrai de vrai, pas de tableau de tableaux), vous aurez besoin de passer 2 blocs de données:
Et ce sont ces deux valeurs distinctes, que ce soit en C ou C++ ou avec VLA ou sans ou autres joyeusetés.
Certaines façons d'écrire que:
Plus simple, fonctionne partout, mais a besoin de plus de travail manuel
VLA, la norme C99
VLA w/reprises des arguments, de l'avant déclaration de paramètre (GNU C extension)
C++ w/VLA (GNU C++ extension, terriblement laid)
Big remarque:
L' [x][y] la notation avec un tableau 2D fonctionne, parce que le tableau est de type contient la largeur. Aucune VLA = array types doit être fixé au moment de la compilation.
Donc: Si vous ne pouvez pas utiliser VLA, alors...
Si vous pouvez utiliser VLA (C99 ou C++ de GNU extensions), puis...
Pour le C++,
boost::multi_array
est un choix solide.Une solution de contournement
2D des tableaux, vous pouvez faire deux allocations:
T
(A)T
(B)Puis définissez les pointeurs (A) au point dans les lignes respectives de (B).
Avec cette configuration, vous pouvez simplement transmettre (Un) autour comme un simple
T**
et il se comportera bien avec[x][y]
indexation.Cette solution est bonne pour de la 2D, mais a besoin de plus et de plus standard pour les dimensions supérieures. Il est aussi plus lent que le VLA solution à cause de la couche supplémentaire d'indirection.
Vous pouvez également exécuter dans une solution similaire avec une allocation distincte pour chaque
B
's ligne. En C, cela ressemble à un malloc dans une boucle, et qui est l'analogue de C++de vecteur de vecteurs. Toutefois, cela enlève l'avantage d'avoir tout l'ensemble en un seul bloc.void foo(arr, width) int width; int arr[][width] {}
. inversé args w/ K&R syntaxe. Je n'ai pas vu cela dans la nature encore bien.auto arr = reinterpret_cast<int (&)[][width]>(ptr);
using arrtype = int[][width];
plus jolie quetypedef int arrtype[][width];
int*
type.Il n'y a aucune façon de faire cela, mais vous pouvez utiliser une solution de contournement pour traiter une à 2 dimensions tableau comme un tableau multidimensionnel et puis le reconvertir à un tableau à deux dimensions à l'intérieur de la fonction.