CrabMan
CrabMan

Reputation: 1748

How to pass 2d array to a function?

This code works as it's supposed to do - it prints all ints in the array, but it produces a warning. I would like to know how to do it right and avoid the warning.

#include <stdio.h>
#include <stddef.h>

void print_all(int * array, ptrdiff_t num_rows, ptrdiff_t num_cols) {
    for (ptrdiff_t i = 0; i < num_rows; ++i) {
        for (ptrdiff_t j = 0; j < num_cols; ++j) {
            printf("%d\n", array[num_cols * i + j]);
        }
    }
}


int main() {
    int array[2][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8}
    };
    print_all(array, 2, 4);
}

This is the warning:

$ clang -Wall -Wextra -pedantic -fsanitize=address -std=c11 arrays.c
arrays.c:18:15: warning: incompatible pointer types passing 'int [2][4]' to
      parameter of type 'int *' [-Wincompatible-pointer-types]
    print_all(array, 2, 4);
              ^~~~~
arrays.c:4:22: note: passing argument to parameter 'array' here
void print_all(int * array, ptrdiff_t num_rows, ptrdiff_t num_cols) {
                     ^
1 warning generated.

Having print_all function only accept arrays with some specified number of columns is not acceptable.

Upvotes: 3

Views: 157

Answers (4)

user3386109
user3386109

Reputation: 34829

If your compiler supports variable length arrays (VLA), then you can do this

void print_all(ptrdiff_t num_rows, ptrdiff_t num_cols, int array[num_rows][num_cols]) {
    for (ptrdiff_t i = 0; i < num_rows; ++i) {
        for (ptrdiff_t j = 0; j < num_cols; ++j) {
            printf("%d\n", array[i][j]);
        }
    }
}


int main(void) {
    int array[2][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8}
    };
    print_all(2, 4, array);
}

The num_rows and num_cols parameters must be before the array parameter so that the compiler knows the dimensions of the array. The VLA allows you to use 2D array indexing array[i][j] instead of doing the math yourself.

If you can't use VLAs or don't want to use VLAs, then the solution is simply to pass the address of the first element of the 2D array

print_all(&array[0][0], 2, 4);

Upvotes: 4

too honest for this site
too honest for this site

Reputation: 12263

A 2D array is something like int[rows][cols]. So why not use the same syntax for the function parameter?

void print_all(size_t rows, size_t cols, int array[rows][cols]);

Notice using the correct types for the dimensions, which is not the signed ptrdiff_t, but size_t. You also have to declare the dimension paramters first so they are known for the array declaration.

Like for most usages of arrays, the name of the array is implicitly converted to a pointer to the first element, which is itself a 1D array: int (*)[cols].

Use normal 2D index operators for the elements array[r][c].

In the paramter declaration of the array the outer (rows) length is actually not required and can be omitted: int array [][cols]. But it is good practice to speccify it anyway, at least for documentation purposes.

The whole thing is much the same like for a constant length array. It is called a variable length array (VLA, for obvious reasons) and standard C since C99 (C11 made it optional, though, but any modern compiler should support it).

Use a constant length array with the macros below if you have an ancient compiler.


Sidenote:

Don't use magic numbers. Have the dimensions of the array in main defined as macros and use the macros only:

#define ROWS 2
#define COLS 4

...

int main(void)
{
    int array[ROWS][COLS] = ...;

    print_all(ROWS, COLS, array);
}

(I also used the correct signature of main; an empty parameterlist is deprecated and subject to be removed in a future version of the standard.)

That way you only have to change the macros if you want to change the lengths of the dimensions.

Upvotes: 2

tdao
tdao

Reputation: 17668

Your print_all() is accepting 1D array, but your main is parsing a 2D array, thus the warning.

You may keep your function intact, and change your array to 1D array, and it should work.

void print_all(int * array, ptrdiff_t num_rows, ptrdiff_t num_cols) {
    for (ptrdiff_t i = 0; i < num_rows; ++i) {
        for (ptrdiff_t j = 0; j < num_cols; ++j) {
            printf("%d\n", array[num_cols * i + j]);
        }
    }
}

and in main()

int array[] = {1, 2, 3, 4, 5, 6, 7, 8};

If you keep 2D array in main, then you'll need to change your print_all()

void print_all(int array[][4], ptrdiff_t num_rows) {
    for (ptrdiff_t i = 0; i < num_rows; ++i) {
        for (ptrdiff_t j = 0; j < 4; ++j) {
            printf("%d\n", array[i][j]);
        }
    }
}

and in main

int array[][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8}
};

You must provide the 2nd dimension (4), but can omit the 1st dimension (2); this is 2D array is stored a series of 1D array in memory.

Upvotes: 1

greg
greg

Reputation: 99

Pointer is a pointer. You can ignore/suppress the warning as long as you know how to interpret it in the function. Of course the preferred way of doing it is to use matching types on both ends.

Upvotes: -3

Related Questions