2009-08-16 7 views
2

J'ai une fonction qui prend un pointeur sur un pointeur comme argument.Arrays 2D avec C++

func(double **arr, int i); 

où dans la fonction principale du tableau est défini comme suit:

double arr[][] = //some initialization here; 

Comment puis-je appeler cette fonction de mon code principal. J'ai essayé le suivant mais il donne une erreur

func (&arr); 

Ne fonctionne pas. Toute aide serait très appréciée. Merci

Répondre

10

Un double **p n'est pas la même chose qu'un double[][] a, donc vous ne pouvez pas passer l'un comme l'autre.

En particulier, la variable de tableau à deux dimensions est un bloc (simple!) De mémoire contenant des doubles auquel vous pouvez accéder avec la syntaxe [][]. Ce requiert que le compilateur connaisse la dimension du tableau, afin qu'il puisse calculer le décalage correct pour chaque élément. Il peut également se désintégrer de manière transparente à un pointeur vers ce bloc de mémoire, mais cela perd la compréhension de l'accès à cette mémoire en tant que tableau à deux dimensions: il devient effectivement un pointeur vers le double.

+----+   +---------+---------+---------+ 
| (a---------->) | a[0][0] | a[0][1] | a[0][2] | ... 
+----+   +---------+---------+---------+ 
       | a[1][0] | a[1][2] | ... 
       +---------+---------+ 
        ... 

La chose attendue par la fonction est un pointeur vers un bloc de mémoire qui contient un ou plusieurs pointeurs vers d'autres blocs de doubles contenant de mémoire. Bien que la syntaxe semble similaire, ces deux structures ont une sémantique totalement différente.


Pour une discussion plus complète, voir my answer à un previous questions (qui traitent en fait c, mais les problèmes sont les mêmes).

+0

Alors, comment puis-je passer le tableau à ma fonction? Je suis confus. Je veux le passer à func sans changer sa déclaration. – zack

16

Le type de arr est double[X][Y] - c'est un tableau de tableaux X de Y double - où X et Y dépendent de votre initializers. C'est pas le même que le type de pointeur. Cependant, selon les règles de conversion C, un tableau peut se désintégrer en un pointeur vers son élément. Dans votre cas, le type résultant d'une telle désintégration sera double (*) [Y] - un pointeur vers un tableau de Y doubles. Notez qu'il s'agit d'un pointeur du tableau, et non d'un tableau de pointeurs, il ne se désintègrera donc plus. À ce stade, vous obtenez une incompatibilité de type, puisque votre fonction attend double**.

La façon correcte de gérer cela est de traiter la matrice comme unidimensionnelle et de transmettre la largeur. Alors:

void func(double* arr, int w) { 
    // arr[2][3] 
    arr[2*w + 3] = ...; 
} 


double x[6][8] = { ... }; 
func(&x[0][0], 8); 

En C++, en particulier, si vous avez toujours alloué statiquement tableaux de bien connus (mais différents) types, vous pourrez peut-être utiliser des modèles et des références comme ceci:

template <int W, int H> 
inline void func(const double (&arr)[W][H]) { 
    arr[2][3] = ...; 
} 

double x[6][8] = { ... }; 
func(x); // W and H are deduced automatically 

Cependant, ceci ne fonctionnera pas quand tout ce que vous avez est un pointeur (par exemple quand le tableau est new -alloué, et sa taille est calculée au moment de l'exécution).Dans le cas le plus général, vous devez utiliser des conteneurs C++ à la place. Avec la bibliothèque standard seulement, on utilise généralement vecteur de vecteurs:

#include <vector> 

void func(std::vector<std::vector<double> > arr) { 
    arr[2][3] = ...; 
} 

std::vector<std::vector<double> > x(6, std::vector<double>(8)); 
x[0][0] = ...; 
... 
func(x); 

Si vous pouvez utiliser Boost, il a une très belle bibliothèque multiarray en elle:

void func(boost::multi_array<double, 2> arr) { // 2 means "2-dimensional" 
    arr[2][3] = ...; 
} 

boost::multi_array<double, 2> x(boost::extents[6][8]); 
x[0][0] = ...; 
... 
func(x); 

[EDIT] vous dites que vous ne pouvez pas changer la définition de votre fonction. Si c'est le cas, alors c'est vraiment une fonction traitant son argument comme un tableau de pointeurs, donc vous devriez juste allouer votre structure de données en conséquence. Par exemple:

double x1[8] = { 1, 2, ... }; 
double x2[8] = { 3, 4, ... }; 
... 
double* x[6] = { x1, x2, ... }; 

func(x); 
+0

Nice et complet. Mais alors, si vous ne pouvez pas changer le fn? Il suffit de l'entourer pour que le tableau de tableaux de niveau supérieur soit stack-local (soit stack stack, soit tas de sécurité). C'est-à-dire que le tableau 2d contient lui-même des tableaux 1d contigus, et vous pouvez simplement les pointer. –

+0

Vous pouvez également utiliser la syntaxe d'initialisation sympa pour un ensemble de tableaux 1d séparés et pointer vers ceux-ci. La syntaxe d'initialisation de tableau n'est disponible que sur une portée de niveau supérieur, n'est-ce pas? –

+0

Bon point, je vais éditer. L'initialiseur de tableau est disponible dans n'importe quelle portée (y compris local/auto), mais pas dans 'new'. –

-1
func(double *arr[100]) 

Vous devez dire au compilateur la taille de la dimension afin qu'il puisse créer l'adresse correcte

arr[y][x] 

se transforme en

arr[100*x+y] 

Si vous définissez votre fonction en tant que func (double ** a) alors vous dites un pointeur vers un tableau de pointeurs comme dmckee a signalé