C Language                
            Przekaż tablice 2D do funkcji
        
        
            
    Szukaj…
Przekaż tablicę 2D do funkcji
Przekazywanie tablicy 2d do funkcji wydaje się proste i oczywiste i z przyjemnością piszemy:
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLS 2
void fun1(int **, int, int);
int main()
{
  int array_2D[ROWS][COLS] = { {1, 2}, {3, 4}, {5, 6} };
  int n = ROWS;
  int m = COLS;
  fun1(array_2D, n, m);
  return EXIT_SUCCESS;
}
void fun1(int **a, int n, int m)
{
  int i, j;
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, a[i][j]);
    }
  }
}
Ale kompilator, tutaj GCC w wersji 4.9.4, nie docenia go dobrze.
$ gcc-4.9 -O3 -g3  -W -Wall -Wextra  -std=c11 passarr.c -o passarr
passarr.c: In function ‘main’:
passarr.c:16:8: warning: passing argument 1 of ‘fun1’ from incompatible pointer type
   fun1(array_2D, n, m);
        ^
passarr.c:8:6: note: expected ‘int **’ but argument is of type ‘int (*)[2]’
 void fun1(int **, int, int);
Przyczyny tego są dwojakie: główny problem polega na tym, że tablice nie są wskaźnikami, a drugą niedogodnością jest tak zwane zanikanie wskaźnika . Przekazanie tablicy do funkcji spowoduje rozpad tablicy na wskaźnik do pierwszego elementu tablicy - w przypadku tablicy 2d rozkłada się na wskaźnik do pierwszego wiersza, ponieważ w C tablice są sortowane od pierwszego rzędu.
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLS 2
void fun1(int (*)[COLS], int, int);
int main()
{
  int array_2D[ROWS][COLS] = { {1, 2}, {3, 4}, {5, 6} };
  int n = ROWS;
  int m = COLS;
  fun1(array_2D, n, m);
  return EXIT_SUCCESS;
}
void fun1(int (*a)[COLS], int n, int m)
{
  int i, j;
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, a[i][j]);
    }
  }
}
Konieczne jest podanie liczby wierszy, nie można ich obliczyć.
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLS 2
void fun1(int (*)[COLS], int);
int main()
{
  int array_2D[ROWS][COLS] = { {1, 2}, {3, 4}, {5, 6} };
  int rows = ROWS;
  /* works here because array_2d is still in scope and still an array */
  printf("MAIN: %zu\n",sizeof(array_2D)/sizeof(array_2D[0]));
  fun1(array_2D, rows);
  return EXIT_SUCCESS;
}
void fun1(int (*a)[COLS], int rows)
{
  int i, j;
  int n, m;
  n = rows;
  /* Works, because that information is passed (as "COLS").
     It is also redundant because that value is known at compile time (in "COLS"). */
  m = (int) (sizeof(a[0])/sizeof(a[0][0]));
 
  /* Does not work here because the "decay" in "pointer decay" is meant
     literally--information is lost. */
  printf("FUN1: %zu\n",sizeof(a)/sizeof(a[0]));
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, a[i][j]);
    }
  }
}
Liczba kolumn jest predefiniowana, a zatem stała w czasie kompilacji, ale poprzednik obecnego standardu C (czyli ISO / IEC 9899: 1999, obecnie ISO / IEC 9899: 2011) wdrożył VLA (TODO: link to) i chociaż obecny standard uczynił go opcjonalnym, prawie wszystkie współczesne kompilatory C obsługują go (TODO: sprawdź, czy MS Visual Studio obsługuje go teraz).
#include <stdio.h>
#include <stdlib.h>
/* ALL CHECKS OMMITTED!*/
void fun1(int (*)[], int rows, int cols);
int main(int argc, char **argv)
{
  int rows, cols, i, j;
  if(argc != 3){
     fprintf(stderr,"Usage: %s rows cols\n",argv[0]);
     exit(EXIT_FAILURE);
  }
  rows = atoi(argv[1]);
  cols = atoi(argv[2]);
  int array_2D[rows][cols];
  for (i = 0; i < rows; i++) {
    for (j = 0; j < cols; j++) {
      array_2D[i][j] = (i + 1) * (j + 1);
      printf("array[%d][%d]=%d\n", i, j, array_2D[i][j]);
    }
  }
  fun1(array_2D, rows, cols);
  exit(EXIT_SUCCESS);
}
void fun1(int (*a)[], int rows, int cols)
{
  int i, j;
  int n, m;
  n = rows;
  /* Does not work anymore, no sizes are specified anymore
  m = (int) (sizeof(a[0])/sizeof(a[0][0])); */
  m = cols;
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, a[i][j]);
    }
  }
}
To nie działa, kompilator narzeka:
$ gcc-4.9 -O3 -g3  -W -Wall -Wextra  -std=c99 passarr.c -o passarr
passarr.c: In function ‘fun1’:
passarr.c:168:7: error: invalid use of array with unspecified bounds
       printf("array[%d][%d]=%d\n", i, j, a[i][j]);
 Staje się nieco jaśniejszy, jeśli celowo popełniamy błąd w wywołaniu funkcji, zmieniając deklarację na void fun1(int **a, int rows, int cols) . To powoduje, że kompilator narzeka w inny, ale równie mglisty sposób 
$ gcc-4.9 -O3 -g3  -W -Wall -Wextra  -std=c99 passarr.c -o passarr
passarr.c: In function ‘main’:
passarr.c:208:8: warning: passing argument 1 of ‘fun1’ from incompatible pointer type
   fun1(array_2D, rows, cols);
        ^
passarr.c:185:6: note: expected ‘int **’ but argument is of type ‘int (*)[(sizetype)(cols)]’
 void fun1(int **, int rows, int cols);
Możemy zareagować na kilka sposobów, jednym z nich jest zignorowanie wszystkiego i wykonanie nieczytelnego żonglowania wskaźnikiem:
#include <stdio.h>
#include <stdlib.h>
/* ALL CHECKS OMMITTED!*/
void fun1(int (*)[], int rows, int cols);
int main(int argc, char **argv)
{
  int rows, cols, i, j;
  if(argc != 3){
     fprintf(stderr,"Usage: %s rows cols\n",argv[0]);
     exit(EXIT_FAILURE);
  }
  rows = atoi(argv[1]);
  cols = atoi(argv[2]);
  int array_2D[rows][cols];
  printf("Make array with %d rows and %d columns\n", rows, cols);
  for (i = 0; i < rows; i++) {
    for (j = 0; j < cols; j++) {
      array_2D[i][j] = i * cols + j;
      printf("array[%d][%d]=%d\n", i, j, array_2D[i][j]);
    }
  }
  fun1(array_2D, rows, cols);
  exit(EXIT_SUCCESS);
}
void fun1(int (*a)[], int rows, int cols)
{
  int i, j;
  int n, m;
  n = rows;
  m = cols;
  printf("\nPrint array with %d rows and %d columns\n", rows, cols);
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, *( (*a) + (i * cols + j)));
    }
  }
}
 Lub robimy to dobrze i przekazujemy potrzebne informacje fun1 . Aby to zrobić, musimy przestawić argumenty na fun1 : rozmiar kolumny musi fun1 się przed deklaracją tablicy. Aby była bardziej czytelna, zmienna zawierająca liczbę wierszy również zmieniła swoje miejsce i jest teraz pierwsza. 
#include <stdio.h>
#include <stdlib.h>
/* ALL CHECKS OMMITTED!*/
void fun1(int rows, int cols, int (*)[]);
int main(int argc, char **argv)
{
  int rows, cols, i, j;
  if(argc != 3){
     fprintf(stderr,"Usage: %s rows cols\n",argv[0]);
     exit(EXIT_FAILURE);
  }
  rows = atoi(argv[1]);
  cols = atoi(argv[2]);
  int array_2D[rows][cols];
  printf("Make array with %d rows and %d columns\n", rows, cols);
  for (i = 0; i < rows; i++) {
    for (j = 0; j < cols; j++) {
      array_2D[i][j] = i * cols + j;
      printf("array[%d][%d]=%d\n", i, j, array_2D[i][j]);
    }
  }
  fun1(rows, cols, array_2D);
  exit(EXIT_SUCCESS);
}
void fun1(int rows, int cols, int (*a)[cols])
{
  int i, j;
  int n, m;
  n = rows;
  m = cols;
  printf("\nPrint array with %d rows and %d columns\n", rows, cols);
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, a[i][j]);
    }
  }
}
Wydaje się to dziwne dla niektórych osób, które uważają, że kolejność zmiennych nie powinna mieć znaczenia. Nie stanowi to większego problemu, wystarczy zadeklarować wskaźnik i pozwolić mu wskazać tablicę.
#include <stdio.h>
#include <stdlib.h>
/* ALL CHECKS OMMITTED!*/
void fun1(int rows, int cols, int **);
int main(int argc, char **argv)
{
  int rows, cols, i, j;
  if(argc != 3){
     fprintf(stderr,"Usage: %s rows cols\n",argv[0]);
     exit(EXIT_FAILURE);
  }
  rows = atoi(argv[1]);
  cols = atoi(argv[2]);
  int array_2D[rows][cols];
  printf("Make array with %d rows and %d columns\n", rows, cols);
  for (i = 0; i < rows; i++) {
    for (j = 0; j < cols; j++) {
      array_2D[i][j] = i * cols + j;
      printf("array[%d][%d]=%d\n", i, j, array_2D[i][j]);
    }
  }
  // a "rows" number of pointers to "int". Again a VLA
  int *a[rows];
  // initialize them to point to the individual rows
  for (i = 0; i < rows; i++) {
      a[i] = array_2D[i];
  }
  fun1(rows, cols, a);
  exit(EXIT_SUCCESS);
}
void fun1(int rows, int cols, int **a)
{
  int i, j;
  int n, m;
  n = rows;
  m = cols;
  printf("\nPrint array with %d rows and %d columns\n", rows, cols);
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("array[%d][%d]=%d\n", i, j, a[i][j]);
    }
  }
}
Używanie płaskich tablic jako tablic 2D
Często najłatwiejszym rozwiązaniem jest po prostu przekazywanie tablic 2D i wyższych jako płaskiej pamięci.
/* create 2D array with dimensions determined at runtime */
double *matrix = malloc(width * height * sizeof(double));
/* initialise it (for the sake of illustration we want 1.0 on the diagonal) */
int x, y;
for (y = 0; y < height; y++)
{
    for (x = 0; x < width; x++)
    {
        if (x == y)
            matrix[y * width + x] = 1.0;
        else
            matrix[y * width + x] = 0.0;
    }
}
/* pass it to a subroutine */
 manipulate_matrix(matrix, width, height);
/* do something with the matrix, e.g. scale by 2 */
void manipulate_matrix(double *matrix, int width, int height)
{
    int x, y;
    for (y = 0; y < height; y++)
    {
        for (x = 0; x < width; x++) 
        {
            matrix[y * width + x] *= 2.0;
        }
    }
}