lakshmen
lakshmen

Reputation: 29084

Correct way of passing 2 dimensional array into a function

I have a 2-dimensional array and I am passing it into a function to carry out certain operations. I'd like to know the correct way of doing it...

#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("%i\t",p[i][j]);
        }
        printf("\n");
    }
}

int main() {
    display(arr);
}

I get an error message:

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

Is this the correct way of passing a 2-dimensional array into a function? If not, what is the correct way?

Upvotes: 55

Views: 148328

Answers (6)

Varun Chhangani
Varun Chhangani

Reputation: 1206

You are doing in wrong way. You can pass 2-d array with the help of pointer to an array, or simply pass an array or through Single pointer.

#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);
}

Upvotes: 6

Mav55
Mav55

Reputation: 4280

You can change the signature of display method as follows:

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

Here, p is a pointer to the row of a 2D array. The pointer only needs to know the number of columns in the array.

Actually speaking, pointer need to know the size of each row. This is very important for pointer arithmetic. So that when you increment the pointer, the pointer must point to next row.

Note here, p is not a normal integer pointer. It's a integer pointer to the memory size equal to integer_size x columns.

In main you don't need to change anything. display(arr) is just fine.

Upvotes: 0

lord.garbage
lord.garbage

Reputation: 5970

There are several, sometimes equivalent ways of doing this. By declaring an array (cf. method_c()), by using a pointer (cf. method_b()) or by using a pointer to an array of an array (cf. method_a()). method_b(), using a single pointer, is slightly more difficult to get right since it is not easy to use standard array indexing and hence, we use pointer arithmetic. method_a() and method_c() are basically equivalent since arrays decay non-recursively to pointers during compilation. Here is a little program illustrating all three methods. We first initialize a 2x4-array arr in a simple for loop and print it. It will look like this:

arr:
0 1 2 3
0 1 2 3

Afterwards we call all three methods. method_a() adds 1, method_b() adds 2 and method_c() adds 3 to all elements. After each call we print out the array arr again. If a function worked correctly you will easily see it on the output. Size is arbitrary and can be regulated via the two macros ROW and COL. One last note, method_c() relies on variable-length array present since 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;
        }
    }
}

Upvotes: 6

Patrick Schl&#252;ter
Patrick Schl&#252;ter

Reputation: 11841

Declare it simply

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

This way your p pointer conveys all necessary informations and you can extract all the dimensions from it without repeating numCols and numRows over and over.

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]);
   }
}

This is particularly interesting if you use typedefs (which I don't like btw)

 typedef int matrix[5][6];

In that case the dimensions are not visible in the signature of the function but the function will still have the correct values for the dimensions.

Upvotes: 0

asaelr
asaelr

Reputation: 5456

If (like in your case), you know the dimensions of the array at compilation-time, you can write justvoid display(int p[][numCols]).

Some explanation: You probably know that when you pass an array to a function, you actually pass a pointer to the first member. In C language, 2D array is just an array of arrays. Because of that, you should pass the function a pointer to the first sub-array in the 2D array. So, the natural way, is to say int (*p)[numCols] (that means p is a pointer, to an array of numCols ints). In function declaration, you have the "shortcut" p[], that means exactly the same thing like (*p) (But tells the reader, that you pass a pointer to a beginning of array, and not to just an one variable)

Upvotes: 13

cnicutar
cnicutar

Reputation: 182664

You should declare your function like this:

void display(int p[][numCols])

This C FAQ thoroughly explains why. The gist of it is that arrays decay into pointers once, it doesn't happen recursively. An array of arrays decays into a pointer to an array, not into a pointer to a pointer.

Upvotes: 72

Related Questions