Manière correcte de passer un tableau 2 dimensions dans une fonction

J'ai un tableau à 2 dimensions et je le passe dans une fonction pour effectuer certaines opérations. J'aimerais connaître la bonne façon de faire...

#define numRows 3
#define numCols 7
#define TotalNum (numRows*numCols)
int arr[numRows][numCols] = {{0,1,2,3,4,5,6}, {7,8,9,10,11,12,13},{14,15,16,17,18,19,20}};

void display(int **p)
{
    printf("n");
    for (int i = 0; i< numRows;i++)
    {
        for ( int j = 0;j< numCols;j++)
        {
            printf("%it",p[i][j]);
        }
        printf("n");
    }
}

int main() {
    display(arr);
}

Je reçois un message d'erreur:

'display': cannot convert parameter1 from 'int' to 'int*'

Est-ce la bonne façon de passer un tableau à 2 dimensions dans une fonction? Si non, quelle est la bonne façon?

50
c
demandé sur Gandaro 2012-02-25 22:20:30

6 réponses

Vous devriez déclarer votre fonction comme ceci:

void display(int p[][numCols])

Cette FAQ C explique en détail pourquoi. L'essentiel est que les tableaux se désintègrent en pointeurs Une fois , cela n'arrive pas récursivement. Un tableau de tableaux se désintègre en un pointeur sur un tableau, pas un pointeur vers un pointeur.

69
répondu cnicutar 2012-02-25 18:23:28

Si (comme dans votre cas), vous connaissez les dimensions du tableau au moment de la compilation, vous pouvez écrire juste void display(int p[][numCols]).

Quelques explications: vous savez probablement que lorsque vous passez un tableau à une fonction, vous passez un pointeur au premier membre. En langage C, le tableau 2D est juste un tableau de tableaux. Pour cette raison, vous devriez passer la fonction un pointeur sur le premier sous-tableau du tableau 2D. Donc, de façon naturelle, est-à-dire int (*p)[numCols] (qui signifie p est un pointeur vers un tableau de numCols ints ). Dans la déclaration de fonction, vous avez le "raccourci" p[], cela signifie exactement la même chose que (*p) (mais dit au lecteur, que vous passez un pointeur sur un début de tableau, et pas seulement une variable)

13
répondu asaelr 2012-02-25 18:29:06

Vous faites dans le mauvais sens. Vous pouvez passer un tableau 2-d à l'aide d'un pointeur sur un tableau, ou simplement passer un tableau ou via un seul pointeur.

#define numRows 3
#define numCols 7
void display(int (*p)[numcols],int numRows,int numCols)//First method//
void display(int *p,int numRows,int numCols) //Second Method//
void display(int numRows,int numCols,int p[][numCols])  //Third Method
{
    printf("\n");
    for (int i = 0; i < numRows;i++)
    {
        for ( int j = 0; j < numCols;j++)
        {
            printf("%i\t",p[i][j]);
        }
        printf("\n");
    }
}

int main() {
    display(arr,numRows,numCols);
}
5
répondu Varun Chhangani 2017-04-22 12:57:26

Il y a plusieurs façons, parfois équivalentes de le faire. En déclarant un tableau (cf. method_c()), en utilisant un pointeur (cf. method_b()) ou en utilisant un pointeur vers un tableau d'un tableau (cf. method_a()). method_b(), en utilisant un seul pointeur, est légèrement plus difficile à obtenir car il n'est pas facile d'utiliser l'indexation de tableau standard et, par conséquent, nous utilisons l'arithmétique du pointeur. method_a() et method_c() sont fondamentalement équivalents puisque les tableaux se désintègrent de manière non récursive aux pointeurs pendant la compilation. Voici un petit programme illustrant les trois méthodes. Nous initialisons d'abord un 2x4-array arr dans une boucle for simple et l'imprimons. Cela ressemblera à ceci:

arr:
0 1 2 3
0 1 2 3

Ensuite, nous appelons les trois méthodes. method_a() ajoute 1, method_b() ajoute 2 et method_c() ajoute 3 à tous les éléments. Après chaque appel, Nous imprimons à nouveau le tableau arr. Si une fonction a fonctionné correctement, vous le verrez facilement sur la sortie. La taille est arbitraire et peut être réglée via les deux macros ROW et COL. Une dernière note, method_c() repose sur une longueur variable tableau présent depuis C99.

#include <stdio.h>
#include <stdlib.h>

#define ROW 2
#define COL 4

void method_a(int m, int n, int (*ptr_arr)[n]);
void method_b(int m, int n, int *ptr_arr);
void method_c(int m, int n, int arr[][n]);

int main(int argc, char *argv[]) {

    int arr[ROW][COL];

    int i;
    int j;
    for(i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            arr[i][j] = j;
        }
    }

    printf("Original array:\n");
    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    method_a(ROW, COL, arr);

    printf("method_a() array:\n");
    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    printf("method_b() array:\n");
    method_b(ROW, COL, (int *)arr);

    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    method_c(ROW, COL, arr);

    printf("method_c() array:\n");
    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    return EXIT_SUCCESS;
}

void method_a(int m, int n, int (*ptr_arr)[n])
{
    int i, j;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            ptr_arr[i][j] = j + 1;
        }
    }
}

void method_b(int m, int n, int *ptr_arr)
{
    int i, j;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            /* We need to use pointer arithmetic when indexing. */
            *((ptr_arr + i * n) + j) = j + 2;
        }
    }
    /* The whole function could have also been defined a bit different by taking
     * the i index out of the pointer arithmetic. n alone will then provide our
     * correct offset to the right. This may be a bit easier to understand. Our
     * for-loop would then look like this:
     * for (i = 0; i < m; i++)
     * {
     *     for (j = 0; j < n; j++)
     *     {
     *         *((ptr_arr + n) + j) = j + 2;
     *     }
     *     ptr_arr++;
     * }*/
}

void method_c(int m, int n, int arr[][n])
{
    int i, j;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            arr[i][j] = j + 3;
        }
    }
}
4
répondu lord.garbage 2015-05-11 08:35:33

Déclarez-le simplement

void display(int (*p)[numCols][numRows]);

Votre p pointeur transmet toutes les informations nécessaires et vous pouvez extraire toutes les dimensions, sans répéter numCols et numRows plus et plus.

void display(int (*p)[numCols][numRows])
{
   size_t i, j;

   printf("sizeof array=%zu\n", sizeof *p);
   printf("sizeof array[]=%zu\n", sizeof **p);
   printf("sizeof array[][]=%zu\n", sizeof ***p);

   size_t dim_y = sizeof *p / sizeof **p;
   printf("dim_y = %zu\n", dim_y);

   size_t dim_x = sizeof **p / sizeof ***p;
   printf("dim_x = %zu\n", dim_x);

   for(i=0; i<dim_y; i++) {
      puts("");
      for(j=0; j<dim_x; j++)
         printf(" %6d", (*p)[i][j]);
   }
}

Ceci est particulièrement intéressant si vous utilisez typedefs (que je n'aime pas btw)

 typedef int matrix[5][6];

, Dans ce cas, les dimensions ne sont pas visibles dans la signature de la fonction, mais la fonction aurez toujours les valeurs correctes pour les dimensions.

0
répondu Patrick Schlüter 2013-06-10 13:20:14

, Vous pouvez modifier la signature de la méthode d'affichage comme suit:

void display(int (*p)[numCols])

Ici p est un pointeur vers la ligne d'un tableau 2D. Le pointeur n'a besoin de connaître le nombre de colonnes dans le tableau.

En fait, le pointeur doit connaître la taille de chaque ligne. Ceci est très important pour l'arithmétique des pointeurs. De sorte que lorsque vous incrémentez le pointeur, le pointeur doit pointer sur la ligne suivante.

Notez ici, p n'est pas un pointeur entier normal. C'est un pointeur entier vers la mémoire taille égale à integer_size x columns.

Dans main, vous n'avez pas besoin de changer quoi que ce soit. display(arr) est très bien.

0
répondu Mav55 2015-12-11 04:36:09