Reputation: 1748
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
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
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
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
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