Ankur Agarwal
Ankur Agarwal

Reputation: 24778

Passing a 2-d array to a function

I have been able to come up with following ways of sending a 2-d array to the function:

#include <stdio.h>

# define NUM_TWO_DIM_ROWS 3
# define NUM_TWO_DIM_COLS 5

void iterate_two_dim(int[][NUM_TWO_DIM_COLS]);
void iterate_two_dim1(int (*)[NUM_TWO_DIM_COLS]);
void iterate_two_dim2(int *);

int main() {

    int two_dim[][NUM_TWO_DIM_COLS] = { //note the second dimension needs to be specified to resolve expression like two_dim[1]
                        {1,2,3,4,5},    // second dimension tells how many integers to move the two_dim pointer
                        {6,7,8,9,10},
                        {11,12,13,14,15}
                    };

    iterate_two_dim(two_dim);
    iterate_two_dim1(two_dim);
    iterate_two_dim2(*two_dim);


}

void iterate_two_dim(int two_dim[][NUM_TWO_DIM_COLS]) { //function parameter uses array notation
    printf("Two dim array passed using array notation\n" );
    for(int row = 0; row < NUM_TWO_DIM_ROWS; row++) {
        for(int col = 0; col < NUM_TWO_DIM_COLS; col++) {
            printf("two_dim[%d][%d] = %-4d  ", row,col, two_dim[row][col] );
        }
        printf("\n");
    }
    printf("\n");
}

void iterate_two_dim1(int (*two_dim)[NUM_TWO_DIM_COLS]) { //function parameter uses pointer notation
    printf("Two dim array passed using pointer notation\n" );
    for(int row = 0; row < NUM_TWO_DIM_ROWS; row++) {
        for(int col = 0; col < NUM_TWO_DIM_COLS; col++) {
            printf("two_dim[%d][%d] = %-4d  ", row,col, two_dim[row][col] );
        }
        printf("\n");
    }
    printf("\n");
}

void iterate_two_dim2(int *two_dim) { //function parameter uses pointer notation
    printf("Two dim array passed using pointer notation\n" );
    char buffer[100];
    for(int count = 0; count < NUM_TWO_DIM_ROWS * NUM_TWO_DIM_COLS; count++) {
            if(count > 0 && count % NUM_TWO_DIM_COLS == 0 )
                printf("\n");
            snprintf(buffer, 40, "two_dim[%d] = %2d", count, two_dim[count] );
            printf("%-20s", buffer );
        }
        printf("\n");
}

Any other ways one can think of for this code where array two_dim is declared and initialized as shown?

Upvotes: 0

Views: 83

Answers (2)

Peter - Reinstate Monica
Peter - Reinstate Monica

Reputation: 16112

A fourth way would be to pass a typed pointer to the whole array, as I alluded in a comment. I didn't test the code but you'll get the idea. Note that *two_dim_ptr is the whole 2D-array, and sizeof(*two_dim_ptr) is the number of all elements times the size of int (it's one of the few cases where an array expression doesn't decay to a pointer).

**two_dim_ptr is the first element of the 2-D array, a one-dimensional array with NUM_TWO_DIM_COLS elements. Consequently, sizeof(*two_dim_ptr)/sizeof(**two_dim_ptr) computes the number of rows.

***two_dim_ptr is the first row's first element, here an int; Consequently, sizeof(**two_dim_ptr)/sizeof(***two_dim_ptr) computes the number of elements in a row.

Computing the index borders using the size of the elements has the maintenance advantage that the code doesn't need to change if you change the element type or constant names. The downside is that it is harder to read.

void iterate_two_dim_p(int (*two_dim_ptr)[NUM_TWO_DIM_ROWS][NUM_TWO_DIM_COLS]) { //function parameter is pointer to array of specific size
    printf("True pointer to two dim array passed\n" );
    for(int row = 0; row < sizeof(*two_dim_ptr)/sizeof(**two_dim_ptr); row++) {
        for(int col = 0; col < sizeof(**two_dim_ptr)/sizeof(***two_dim_ptr); col++) {
            printf("two_dim_ptr[%d][%d] = %-4d  ", row,col, two_dim_ptr[row][col] );
        }
        printf("\n");
    }
    printf("\n");
}

You'd call it with iterate_two_dim_p(&two_dim);, that is you take the address of the whole array. (The position of argument to the adress operator is another case where arrays do not decay. The result is a properly typed address of a 2-D array, not just the address of its first row. Of course all addresses are numerically identical because the address of a composite type is the address of its first element, a rule which applies recursively, so that (size_t)&two_dim == (size_t)two_dim && (size_t)two_dim == (size_t)*two_dim. The difference is in the types.)

Upvotes: 1

The ways 1 and 2 are the same (and the correct ones). An argument of array of type is adjusted to an argument of type pointer to type, i.e. int[][NUM_TWO_DIM_COLS] becomes int (*two_dim)[NUM_TWO_DIM_COLS] after the adjustment.


The way 3 is wrong. You're accessing an array out of bounds. The compiler is allowed to take into the account that the pointer points to the first element of an array of NUM_TWO_DIM_COLS and do bounds-checking against this bound.

C11 Appendix J.2 lists this as undefined behaviour:

An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]) (6.5.6).

Upvotes: 4

Related Questions