incompatible pointer type in C: fix it
Fix incompatible pointer type in C by comparing the type a function expects with the type you passed, without hiding the problem behind a cast.
GCC says "passing argument 3 of 'print_grid' from incompatible pointer type", yet both sides look like addresses. The message does not mean an address is missing. It means the function would read that address using a different shape from the real object.
In short
incompatible pointer type means that the pointer passed to a function does not have the pointer type declared by its parameter. Read both types in the diagnostic, then go back to the function declaration and the expression at the call. Fix the contract or the object you passed, without adding a cast to silence GCC: a cast can hide a memory read that does not match the actual layout of the data.
What are the two lines in the diagnostic comparing?
The diagnostic gives the call location, parameter number, expected type, and the type your expression produces. Start with the last two pieces, not with the pointer value itself.
#include <stddef.h>
void print_grid(size_t rows, size_t cols, int **grid){ (void)rows; (void)cols; (void)grid;}
int main(void){ int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_grid(2, 3, grid); return 0;}$ gcc -std=c23 -Wall -Wextra -Werror bad-grid.c -o bad-gridbad-grid.c: In function 'main':bad-grid.c:14:22: error: passing argument 3 of 'print_grid' from incompatible pointer type [-Wincompatible-pointer-types] 14 | print_grid(2, 3, grid); | ^~~~ | | | int (*)[3]bad-grid.c:3:49: note: expected 'int **' but argument is of type 'int (*)[3]' 3 | void print_grid(size_t rows, size_t cols, int **grid) | ~~~~~~^~~~Here, grid is an array of two rows of three int. At the call, it becomes a pointer to its first row, with type int (*)[3]. That is not an int **, which would point to a pointer to an int. Both support grid[row][column], but their memory is laid out differently.
Stack
- int[2][3]gridgrid
- {{1,2,3},{4,5,6}}
- int **lines
- row_pointers
Heap
A 2D array stores its int values one after another. An int ** expects an array of row addresses first. Passing one as the other makes the first int look like an address.
How do you declare a function that receives a 2D array?
The function needs the width of a row to calculate the address of grid[row][column]. When dimensions come at run time, put rows and cols before the array parameter, then write const int grid[rows][cols].
#include <stddef.h>#include <stdio.h>
void print_grid(size_t rows, size_t cols, const int grid[rows][cols]){ for (size_t row = 0; row < rows; row++) { for (size_t column = 0; column < cols; column++) printf("%d%c", grid[row][column], column + 1 == cols ? '\n' : ' '); }}
int main(void){ int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_grid(2, 3, grid); return 0;}$ gcc -std=c23 -Wall -Wextra -Werror good-grid.c -o good-grid$ ./good-grid1 2 34 5 6const tells the reader that print_grid reads the array without changing it. It does not "convert" the type. [cols] is what preserves the width of a row in the parameter type.
sum_range
sum-range asks you to pass a pointer and a length to a function. Read each parameter before writing the call: a range of int is a const int *, not a pointer to a pointer.
Why are two structs with matching fields still different?
Two separate struct definitions create two separate types. Their fields can have the same names and order, and the compiler still will not mix them.
struct point { int x; int y;};
struct position { int x; int y;};
void move_right(struct point *value){ value->x++;}
int main(void){ struct position value = {4, 9};
move_right(&value); return 0;}$ gcc -std=c23 -Wall -Wextra -Werror bad-struct.c -o bad-structbad-struct.c: In function 'main':bad-struct.c:20:16: error: passing argument 1 of 'move_right' from incompatible pointer type [-Wincompatible-pointer-types] 20 | move_right(&value); | ^~~~~~ | | | struct position *bad-struct.c:11:31: note: expected 'struct point *' but argument is of type 'struct position *' 11 | void move_right(struct point *value) | ~~~~~~~~~~~~~~^~~~~The right fix depends on your model: does the function really handle a point or a position? Choose one struct for that data, or write an explicit conversion that copies the fields you mean to copy. Renaming a type or adding (struct point *)&value does not answer that question.
#include <stdio.h>
struct point { int x; int y;};
void move_right(struct point *value){ value->x++;}
int main(void){ struct point value = {4, 9};
move_right(&value); printf("%d %d\n", value.x, value.y); return 0;}$ gcc -std=c23 -Wall -Wextra -Werror good-struct.c -o good-struct$ ./good-struct5 9Does a cast fix incompatible pointer type?
No. A cast tells the compiler to treat an address as another type; it does not change the array or struct behind that address. Use one only when an API documents the conversion and you know how it recovers the original type later. For a function you control, the cast leaves the contract inconsistent and removes the signal that helps you fix it.
Read pointers in C, then array vs pointer in C. If the message uses a different warning name, GCC warnings explained walks through common diagnostics.
Frequently asked questions
Why does GCC mention a pointer when I passed an array?
In most calls, an array becomes a pointer to its first element. For a 2D array, that element is a whole row, so its type keeps the row width.
Can I convert int (*)[3] to int **?
No. The first points to contiguous rows of three int; the second points to row addresses. A cast does not create those missing addresses.
Is the message a warning or an error?
With GCC in C99 or a later dialect, this diagnostic is an error by default. -Werror also makes clear the cases that remain warnings depending on compiler options and version.
Sources
