incompatible pointer type en C : corriger
Corrige l'erreur incompatible pointer type en C en comparant le type attendu et le type passé, sans masquer le problème avec un cast.
GCC affiche « passing argument 3 of 'print_grid' from incompatible pointer type » et tu vois pourtant une adresse des deux côtés. Le message ne dit pas que l'adresse est absente. Il dit que la fonction va lire cette adresse avec une forme différente de celle du vrai objet.
En bref
incompatible pointer type signifie que le pointeur passé à une fonction n'a pas le type de pointeur annoncé par son paramètre. Lis les deux types dans le diagnostic, puis remonte à la déclaration de la fonction et à l'expression de l'appel. Corrige le contrat ou l'objet passé, sans ajouter de cast pour faire taire GCC : un cast peut cacher une lecture mémoire qui ne correspond pas à la disposition réelle des données.
Que comparent les deux lignes du diagnostic ?
Le diagnostic donne la position de l'appel, le numéro du paramètre, le type attendu et celui que l'expression produit. Commence par ces deux derniers morceaux, pas par le pointeur lui-même.
#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) | ~~~~~~^~~~Ici, grid est un tableau de deux lignes de trois int. Lors de l'appel, il devient un pointeur vers sa première ligne, de type int (*)[3]. Ce n'est pas un int **, qui désignerait un pointeur vers un pointeur vers int. Les deux se manipulent avec grid[row][column], mais leur mémoire n'est pas organisée pareil.
Pile (stack)
- int[2][3]gridgrid
- {{1,2,3},{4,5,6}}
- int **lines
- row_pointers
Tas (heap)
Un tableau 2D contient ses int les uns après les autres. Un int ** demande d'abord un tableau d'adresses de lignes. Passer l'un pour l'autre revient à interpréter le premier int comme une adresse.
Comment déclarer une fonction qui reçoit un tableau 2D ?
La fonction doit connaître la largeur d'une ligne pour calculer l'adresse de grid[row][column]. Avec des dimensions reçues à l'exécution, place rows et cols avant le paramètre tableau, puis écris 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 6Le const veut dire que print_grid lit le tableau sans le modifier. Il n'est pas là pour « convertir » le type. Le [cols] est la partie qui conserve la taille d'une ligne dans le type du paramètre.
sum_range
sum-range te fait passer un pointeur et une longueur à une fonction. Lis chaque paramètre avant d'écrire l'appel : une plage d'int est un const int *, pas un pointeur vers un pointeur.
Pourquoi deux structures avec les mêmes champs restent différentes ?
Deux définitions struct distinctes créent deux types distincts. Les champs peuvent avoir les mêmes noms et le même ordre, le compilateur ne les confondra pas.
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) | ~~~~~~~~~~~~~~^~~~~Le bon correctif dépend de ton modèle : la fonction manipule-t-elle vraiment un point ou une position ? Choisis un seul struct pour cette donnée, ou écris une conversion explicite qui copie les champs voulus. Renommer un type ou ajouter (struct point *)&value ne répond pas à cette 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 9Est-ce qu'un cast résout incompatible pointer type ?
Non. Un cast dit au compilateur de traiter une adresse comme un autre type ; il ne transforme ni le tableau ni la structure derrière cette adresse. Il convient seulement quand une API documente cette conversion et que tu sais comment elle récupère ensuite le type original. Pour une fonction que tu contrôles, le cast laisse le contrat incohérent et retire le signal qui t'aide à le corriger.
Relis aussi les pointeurs en C, puis tableau ou pointeur en C. Si le message apparaît avec un warning différent, warnings GCC expliqués donne la lecture des diagnostics les plus courants.
Questions fréquentes
Pourquoi GCC parle d'un pointeur alors que j'ai passé un tableau ?
Dans la plupart des appels, un tableau devient un pointeur vers son premier élément. Pour un tableau 2D, cet élément est une ligne entière, donc son type garde la largeur de la ligne.
Puis-je convertir int (*)[3] en int ** ?
Non. Le premier pointe vers des lignes contiguës de trois int, le second vers des adresses de lignes. Le cast ne crée pas les adresses manquantes.
Est-ce que le message est un warning ou une erreur ?
Avec GCC en C99 ou plus récent, ce diagnostic est une erreur par défaut. -Werror rend aussi visibles les cas qui seraient encore des warnings selon les options et la version du compilateur.
Sources
