Conversion de tableaux multidimensionnels en pointeurs en c ++

J’ai un programme qui ressemble à ceci:

double[4][4] startMasortingx; double[4][4] inverseMasortingx; initialize(startMasortingx) //this puts the information I want in startMasortingx 

Je veux maintenant calculer l’inverse de startMasortingx et le mettre dans inverseMasortingx. J’ai une fonction de bibliothèque à cet effet dont le prototype est le suivant:

 void MasortingxInversion(double** A, int order, double** B) 

cela prend l’inverse de A et le met dans B. Le problème est que je dois savoir convertir le double [4] [4] en un double ** pour donner à la fonction. J’ai juste essayé de le faire “de manière évidente”:

 MasortingxInversion((double**)startMasortingx, 4, (double**)inverseMasortingx)) 

mais cela ne semble pas fonctionner. Est-ce vraiment la bonne façon de le faire?

Non, il n’y a pas de bonne façon de faire cela. Un tableau double[4][4] n’est pas convertible en un double ** pointeur double ** . Ce sont deux manières alternatives et incompatibles d’implémenter un tableau 2D. Quelque chose doit être changé: soit l’interface de la fonction, soit la structure du tableau passée en argument.

Le moyen le plus simple de réaliser cette dernière, c’est-à-dire de rendre votre tableau double[4][4] existant compatible avec la fonction, est de créer des tableaux “d’index” temporaires de type double *[4] pointant vers le début de chaque ligne de chaque ligne. masortingce

 double *startRows[4] = { startMasortingx[0], startMasortingx[1], startMasortingx[2] , startMasortingx[3] }; double *inverseRows[4] = { /* same thing here */ }; 

et passez ces tableaux “d’index” à la place

 MasortingxInversion(startRows, 4, inverseRows); 

Une fois que la fonction a fini de fonctionner, vous pouvez oublier les tableaux startRows et inverseRows , car le résultat sera correctement placé dans votre tableau inverseMasortingx .

Pour une raison donnée, un tableau bidimensionnel (un bloc de mémoire contigu) et un tableau de pointeurs (non contigus) sont des choses très différentes, vous ne pouvez pas transmettre un tableau bidimensionnel à une fonction fonctionnant avec un pointeur à l’autre.

Une chose que vous pouvez faire: des modèles. Définissez la taille de la deuxième dimension en tant que paramètre de modèle.

 #include  template  void print(double a[][N], unsigned order) { for (unsigned y = 0; y < order; ++y) { for (unsigned x = 0; x < N; ++x) { std::cout << a[y][x] << ' '; } std::cout << '\n'; } } int main() { double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}}; print(arr, 3); } 

Une autre manière un peu plus maladroite pourrait être de faire accepter à la fonction un pointeur sur un tableau à une dimension, ainsi que la largeur et la hauteur en tant qu'arguments, et à calculer vous-même les index en une représentation à deux dimensions.

 #include  void print(double *a, unsigned height, unsigned width) { for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { std::cout << a[y * width + x] << ' '; } std::cout << '\n'; } } int main() { double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}}; print(&arr[0][0], 3, 3); } 

Naturellement, une masortingce est quelque chose qui mérite une classe à part (mais ce qui précède peut toujours être pertinent, si vous avez besoin d'écrire des fonctions d'assistance).

Puisque vous utilisez C ++, la meilleure façon de procéder est d’utiliser une classe personnalisée et certains modèles. L’exemple suivant est plutôt brutal, mais il passe le message fondamental.

 #include  using namespace std; template  class SquareMasortingx { public: int size(void) { return masortingx_size; } double array[masortingx_size][masortingx_size]; void copyInverse(const SquareMasortingx & src); void print(void); }; template  void SquareMasortingx::copyInverse(const SquareMasortingx & src) { int inv_x; int inv_y; for (int x = 0; x < matrix_size; x++) { inv_x = matrix_size - 1 - x; for (int y = 0; y < matrix_size; y++) { inv_y = matrix_size - 1 - y; array[x][y] = src.array[inv_x][inv_y]; } } } template  void SquareMasortingx::print(void) { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { cout << array[x][y] << " "; } cout << endl; } } template  void Initialize(SquareMasortingx & masortingx); int main(int argc, char * argList[]) { SquareMasortingx<4> startMasortingx; SquareMasortingx<4> inverseMasortingx; Initialize(startMasortingx); inverseMasortingx.copyInverse(startMasortingx); cout << "Start:" << endl; startMatrix.print(); cout << "Inverse:" << endl; inverseMatrix.print(); return 0; } template  void Initialize(SquareMasortingx & masortingx) { for (int x = 0; x < matrix_size; x++) { for (int y = 0; y < matrix_size; y++) { matrix.array[x][y] = (x+1)*10+(y+1); } } } 

Un tableau à deux dimensions n’est pas un pointeur sur un pointeur ou quelque chose de similaire. Le type correct pour votre startMasortingx est double (*)[4] . Pour votre fonction, la signature devrait être comme:

 MasortingxInversion( double (*A)[4], int order, double (*B)[4] ); 

Il y a une solution qui utilise le pointeur pour pointer un bobobobo

William Sherif (bobobobo) a utilisé la version C et je veux simplement montrer la version C ++ de la réponse de bobobobo.

 int numRows = 16 ; int numCols = 5 ; int **a ; a = new int*[ numRows* sizeof(int*) ]; for( int row = 0 ; row < numRows ; row++ ) { a[row] = new int[ numCols*sizeof(int) ]; } 

Le rest du code est identique à celui de Bobobobo.

Le problème est qu’un tableau à deux dimensions n’est pas la même chose qu’un tableau de pointeurs. Un tableau à deux dimensions stocke les éléments ligne par ligne. Ainsi, lorsque vous passez un tel tableau, seul un pointeur vers le début est indiqué. La fonction de réception peut déterminer comment trouver n’importe quel élément du tableau, mais uniquement si elle connaît la longueur de chaque ligne .

Ainsi, votre fonction de réception doit être déclarée comme étant void MasortingxInversion(double A[4][], int order, double B[4][]) .

en codant bien si c ++:

 struct masortingx { double m[4][4]; }; masortingx startMasortingx; masortingx inverseMasortingx; 

donc l’ interface serait

 void MasortingxInversion(masortingx &A, int order, masortingx &B); 

et l’utiliser

 MasortingxInversion(startMasortingx, 4, inverseMasortingx); 

Le bénéfice

  1. l’interface est très simple et claire.
  2. une fois que vous avez besoin de modifier “m” de la masortingce en interne, vous n’avez pas besoin de mettre à jour l’interface.

Ou de cette façon

 struct masortingx { void Inversion(masortingx &inv, int order) {...} protected: double m[4][4]; }; masortingx startMasortingx; masortingx inverseMasortingx; ... 

Une façon laide en c

 void MasortingxInversion(void *A, int order, void *B); MasortingxInversion((void*)startMasortingx, 4, (void*)inverseMasortingx); 

EDIT: code de référence pour MasortingxInversion qui ne plantera pas:

 void MasortingxInversion(void *A, int order, void *B) { double _a[4][4]; double _b[4][4]; memcpy(_a, A, sizeof _a); memcpy(_b, B, sizeof _b); // processing data here // copy back after done memcpy(B, _b, sizeof _b); }