Le langage C n'a pas vraiment été "conçu" ; au contraire, des fonctionnalités ont été ajoutées au fur et à mesure des besoins, en s'efforçant de ne pas casser le code antérieur. Une telle approche évolutive était une bonne chose à l'époque où le C était en cours de développement, car cela signifiait que, pour la plupart, les développeurs pouvaient récolter les avantages des premières améliorations du langage avant que tout ce que le langage pourrait avoir besoin de faire ne soit élaboré. Malheureusement, la façon dont la gestion des tableaux et des pointeurs a évolué a conduit à une variété de règles qui, rétrospectivement, sont malheureuses.
Dans le langage C d'aujourd'hui, il existe un système de types assez substantiel, et les variables ont des types clairement définis, mais les choses n'ont pas toujours été ainsi. Une déclaration char arr[8]
; allouerait 8 octets dans l'étendue actuelle, et rendrait arr
pointe vers le premier d'entre eux. Le compilateur ne saurait pas que arr
représentait un tableau - il représenterait un pointeur de caractère comme n'importe quel autre tableau. char*
. D'après ce que je comprends, si on avait déclaré char arr1[8], arr2[8];
la déclaration arr1 = arr2;
aurait été parfaitement légal, étant quelque peu équivalent conceptuellement à char *st1 = "foo, *st2 = "bar"; st1 = st2;
mais aurait presque toujours représenté un bug.
La règle selon laquelle les tableaux se décomposent en pointeurs provient d'une époque où les tableaux et les pointeurs étaient vraiment la même chose. Depuis lors, les tableaux ont été reconnus comme un type distinct, mais le langage devait rester essentiellement compatible avec l'époque où ils ne l'étaient pas. Lorsque les règles ont été formulées, la question de la gestion des tableaux bidimensionnels ne se posait pas, car ils n'existaient pas. On pouvait faire quelque chose comme char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5);
et ensuite utiliser bar[x][y]
de la même manière qu'on utiliserait aujourd'hui un tableau à deux dimensions, mais un compilateur ne verrait pas les choses de cette manière - il verrait simplement bar
comme un pointeur vers un pointeur. Si l'on voulait que foo[1] pointe à un endroit complètement différent de foo[2], on pourrait parfaitement le faire légalement.
Lorsque les tableaux à deux dimensions ont été ajoutés au C, il n'était pas nécessaire de maintenir la compatibilité avec le code antérieur qui déclarait les tableaux à deux dimensions, car il n'y en avait pas. Alors qu'il aurait été possible de spécifier que char bar[4][5];
générerait un code équivalent à ce qui a été montré en utilisant l'option foo[20]
Dans ce cas, une char[][]
aurait été utilisable en tant que char**
On a pensé que, de la même manière que l'assignation de variables de tableau aurait été une erreur dans 99% des cas, il en aurait été de même pour la réassignation de lignes de tableau, si cela avait été légal. Ainsi, les tableaux en C sont reconnus comme des types distincts, avec leurs propres règles qui sont un peu étranges, mais qui sont ce qu'elles sont.