30 votes

Pourquoi C aurait-il des "faux tableaux"?

Je suis en train de lire Le Unix haters manuel et dans le chapitre 9, il y a quelque chose que je ne comprends pas vraiment:

C n'a pas vraiment d'avoir des tableaux soit. Il a quelque chose qui ressemble à un tableau mais c'est vraiment un pointeur vers un emplacement de la mémoire.

Je ne peux pas vraiment imaginer un moyen de stocker un tableau dans la mémoire autres que l'utilisation de pointeurs de l'indice des emplacements de mémoire. Comment C implémente les "faux" des tableaux, de toute façon? Est-il sur la véracité de cette allégation?

40voto

zoul Points 51637

Je pense que l'auteur est que C des tableaux sont vraiment juste un mince vernis sur l'arithmétique des pointeurs. L'indice de l'opérateur est définie simplement comme a[b] == *(a + b), de sorte que vous pouvez facilement dire 5[a] au lieu de a[5] et faire d'autres choses horribles comme l'accès le tableau passé le dernier indice.

La comparant à celle, une "vraie tableau" serait celui qui connaît sa propre taille, ne permet pas de faire de l'arithmétique des pointeurs, l'accès au-delà du dernier indice, sans une erreur, ou d'accéder à son contenu à l'aide d'un type d'élément différent. En d'autres termes, un "vrai tableau" est un resserrement de l'abstraction qui n'a pas de cravate vous pour une représentation unique – c'est peut-être une liste liée au lieu, par exemple.

PS. Pour m'épargner quelques difficultés: je n'ai pas vraiment d'opinion sur ce, je vais me contenter d'expliquer la citation du livre.

13voto

user268396 Points 4624

Il y a une différence entre C les tableaux et les pointeurs, et il peut être vu par la sortie de l' sizeof() expressions. Par exemple:

void sample1(const char * ptr)
{
   /* s1 depends on pointer size of architecture */
   size_t s1 = sizeof(ptr); 
}
size_t sample2(const char arr[])
{
   /* s2 also depends on pointer size of architecture, because arr decays to pointer */
   size_t s2 = sizeof(arr); 
   return s2;
}
void sample3(void)
{
   const char arr[3];
   /* s3 = 3 * sizeof(char) = 3 */
   size_t s2 = sizeof(arr); 
}
void sample4(void)
{
   const char arr[3];
   /* s4 = output of sample2(arr) which... depends on pointer size of architecture, because arr decays to pointer */
   size_t s4 = sample2(arr); 
}

L' sample2 et sample4 en particulier est probablement la raison pour laquelle les gens ont tendance à confondre C des tableaux avec C les pointeurs, parce que dans d'autres langues, vous pouvez tout simplement passer des tableaux en argument à une fonction et travail "tout de même", comme on l'a fait en l'appelant la fonction. De même, en raison de la façon dont C fonctionne, vous pouvez passer des pointeurs au lieu des tableaux et c'est "valide", tandis que dans d'autres langues, avec une distinction plus claire entre les tableaux et les pointeurs elle ne serait pas.

Vous pouvez également afficher l' sizeof() sortie comme une conséquence de la C-passer-par-valeur sémantique (puisque C des tableaux de décroissance de pointeurs).

Aussi, certains compilateurs également en charge ce la syntaxe du C:

void foo(const char arr[static 2])
{
   /* arr must be **at least** 2 elements in size, cannot pass NULL */
}

12voto

AndreyT Points 139512

La déclaration que vous avez cité est en fait incorrect. Les tableaux en C ne sont pas des pointeurs.

L'idée de la mise en œuvre des tableaux de pointeurs a été utilisé dans B et BCPL langues (les ancêtres de C), mais il n'a pas survécu à la transition à C. À l'âge précoce de C la "compatibilité ascendante" avec B et BCPL a été considérée comme peu importante, c'est pourquoi C des tableaux étroitement émuler le comportement de B et de BCPL tableaux (c'est à dire C des tableaux facilement "désintégration" de pointeurs). Néanmoins, C des tableaux ne sont pas des "pointeurs vers un emplacement de la mémoire".

Le livre de devis est totalement faux. Cette idée fausse assez répandue parmi les C débutants. Mais comment il a réussi à entrer dans un livre, c'est au delà de moi.

8voto

hyde Points 13720

Auteur signifie probablement que les tableaux sont limités dans les moyens qui les font se sentir comme des citoyens de 2ème zone de programmeur point de vue. Par exemple, deux fonctions, l'une est ok, l'autre n'est pas:

int finefunction() {
    int ret = 5;
    return ret;
}

int[] wtffunction() {
    int ret[1] = { 5 };
    return ret;
}

Vous pouvez contourner ce un peu en enveloppant les tableaux dans les structures, mais c'est juste souligne que les tableaux sont différents, ils ne sont pas comme les autres types.

struct int1 {
    int a[1];
}

int[] finefunction2() {
    struct int1 ret = { { 5 } };
    return ret;
}

Un autre effet de cette est que vous ne pouvez pas obtenir la taille du tableau au moment de l'exécution:

int my_sizeof(int a[]) {
    int size = sizeof(a);
    return size;
}

int main() {
    int arr[5];
    // prints 20 4, not 20 20 as it would if arrays were 1st class things
    printf("%d %d\n", sizeof(arr), my_sizeof(arr)); 
}

Une autre façon de dire ce que les auteurs ont dit que, dans C (et C++) de la terminologie, "array" signifie quelque chose d'autre que dans la plupart des autres langues.


Ainsi, le titre de votre question, comment un "vrai tableau" être stockées dans la mémoire. Eh bien, il n'y a pas une seule sorte de "vrai tableau". Si vous voulais de vrais tableaux en C, vous avez deux options:

  1. Utiliser calloc d'allouer de la mémoire tampon, et de stocker le pointeur et le nombre d'éléments ici

    struct intarrayref {
      size_t count;
      int *data;
    }
    

    Cette structure est essentiellement référence à un tableau, et vous pouvez les passer bien des fonctions, etc. Vous allez écrire des fonctions d'opérer sur elle, comme créer une copie des données réelles.

  2. Utilisation flexible de membre du groupe, et d'allouer de l'ensemble de la structure avec un seul calloc

    struct intarrayobject {
        size_t count;
        int data[];
    }
    

Dans ce cas, vous allouez à la fois les métadonnées (count), et l'espace de la matrice de données en une seule fois, mais le prix est, vous ne pouvez pas passer cette structure autour de la valeur, pas plus, parce que ce serait de laisser derrière les données supplémentaires. Vous devez passer un pointeur vers cette structure, des fonctions, etc. Donc, il est question d'opinion si l'on considère ceci comme un "vrai tableau" ou juste un peu amélioré normal C tableau.

7voto

R.. Points 93718

Comme tout le livre, c'est un cas de pêche à la traîne, en particulier, le type de pêche à la traîne qui implique de dire quelque chose de presque vrai mais de mal pour solliciter des réponses en colère sur la raison pour laquelle c'est mal. C a très certainement des tableaux / types de tableaux réels, comme en témoigne le fonctionnement des types pointeur sur tableau (et tableaux multidimensionnels).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X