13Fermer15
PpHdLe 04/01/2014 à 17:52
Un tableau est un pointeur ne sont pas la même chose, sauf dans le cas des paramètres de fonction (cf. http://c-faq.com/aryptr/aryptr2.html )
Du point de vue sémantique, un tableau est une collection d'objets de même type, d'adresse fixe et de taille fixe. Un pointeur est une référence (une adresse) vers un objet (cf. http://c-faq.com/aryptr/practdiff.html )
Là où le C est problématique est que partout où on utilise un tableau( sauf exceptions mineures style sizeof + initialisation), à l'utilisation, on a une conversion implicite d'un tableau en pointeur vers son premier élément (cf. http://c-faq.com/aryptr/aryptrequiv.html ). En fait, c'est que l'arithmétique de pointeurs et l'indexage de tableau sont la même chose: a[b] = *(a+b) (et c'est la norme C qui l'impose !)

On aurait pu imaginer que le C n'autorise pas l'arithmétique sur les pointeurs, et qu'il faille écrire:
 int n = ....;
 int (*p)[n] = calloc (n, sizeof(int));
 for(int i = 0; i < n; i++)
   (*p)[i] = i;

au lieu de :
 int n = ....;
 int *p = calloc (n, sizeof(int));
 for(int i = 0; i < n; i++)
   p[i] = i;

car p n'est pas un pointeur sur un entier, mais un pointeur vers un tableau d'entier, et c'est l'arithmétique sur les pointeurs + l'équivalence ci dessus qui permet d'écrire ce code simplifié.

Certaines personnes pensent que ca serait plus propre parce que les débutants ne comprennent pas la différence entre les deux expressions suivantes :
 char *str = "toto";
 char str[] = "toto";


Le risque présenté (sizeof d'un paramètre d'entrée du service) est assez faible après tout (Je n'ai jamais utilisé l'opérateur sizeof sur un paramètre d'entrée d'un service !).
Mais d'un autre coté, on peut imaginer que si l'on écrit
 void f(const int tab[])

des gens soient tentés de le faire pour calculer la taille du tableau passé en paramètre (et comment leur expliquer que non sans rentrer dans les détails sordides du C!)

On voit bien au final que les tableaux sont des objets de seconde classe dans la norme C...
(Par exemple, on a le fameux exemple où pour passer x en paramètre à f sans warning, on s'arrache les cheveux :
 void f(const int n[3][3]) { ...}
 int x[3][3];
)

Bref, c'est aussi pour çà que j'ai ouvert la discussion !