2010-11-08 6 views
54

En C++, quelle est la différence (le cas échéant) entre l'utilisation de char et char [1].Différence entre char et char [1]

exemples:

struct SomeStruct 
{ 
    char x; 
    char y[1]; 
}; 

Ne les mêmes raisons suivantes pour unsigned char?

+18

La quantité de mauvaises réponses à cette question est stupéfiante. +1 pour demander quelque chose apparemment les gens malentendent souvent. –

+2

J'ai lu cette question et pourrais presque ici les centaines de claviers tapant furieusement pour être les premiers à répondre. – Anthony

+2

@Billy, @Duracell: Malheureusement, la plupart des programmeurs C et C++ ne comprennent pas vraiment les tableaux. D'une part, c'est quelque peu surprenant, compte tenu de leur caractère fondamental; d'un autre côté, la désintégration des tableaux et la façon dont fonctionne l'indice permettent aux débutants de penser que les tableaux sont la même chose que les pointeurs. –

Répondre

39

La principale différence est simplement la syntaxe que vous utilisez pour accéder à votre un caractère. Par "accès", je veux dire, agir sur lui en utilisant les différents opérateurs dans la langue, la plupart ou tous qui font des choses différentes lorsqu'il est appliqué à un char par rapport à un tableau char. Cela donne l'impression que x et y sont presque entièrement différents. Si c'est le cas, ils "consisteront tous deux" en un seul char, mais ce char a été représenté d'une manière très différente.

La mise en œuvre pourrait cause d'autres différences, par exemple, il pourrait aligner et pad la structure différemment selon lequel vous utilisez. Mais j'en doute.

Un exemple des différences de l'opérateur est qu'un caractère est cessible, et un tableau n'est pas:

SomeStruct a; 
a.x = 'a'; 
a.y[0] = 'a'; 
SomeStruct b; 
b.x = a.x; // OK 
b.y = a.y; // not OK 
b.y[0] = a.y[0]; // OK 

Mais le fait que y est incessible ne s'arrête pas SomeStruct être cessible:

b = a; // OK 

Tout cela est indépendamment du type, char ou non. Un objet d'un type, et un tableau de ce type avec la taille 1, sont à peu près les mêmes en termes de mémoire. En passant, il existe un contexte dans lequel il fait une grande différence que vous "utilisez" sur char et char[1], et qui aide parfois les gens à penser que les tableaux sont vraiment des pointeurs. Pas votre exemple, mais en tant que paramètre de fonction:

void foo(char c);  // a function which takes a char as a parameter 
void bar(char c[1]); // a function which takes a char* as a parameter 
void baz(char c[12]); // also a function which takes a char* as a parameter 

Les chiffres figurant dans les déclarations de bar et baz sont complètement ignorés par le langage C++. Apparemment, quelqu'un à un moment donné a estimé qu'il serait utile aux programmeurs comme une forme de documentation, indiquant que la fonction baz s'attend à ce que son argument pointer pointe sur le premier élément d'un tableau de 12 caractères. Dans c, le type de tableau ne correspond jamais à un type de tableau, mais ce n'est pas le cas. Il s'agit simplement d'une syntaxe de casse spéciale, au sens de char *c. C'est pourquoi j'ai mis les guillemets sur "utiliser" - vous n'utilisez pas du tout char[1], ça ressemble à ça.

+9

+1, je suis fatigué de toutes les réponses en disant que «y» est un pointeur. – casablanca

+4

Belle et claire réponse. Une autre chose qui sera différente est l'initialisation avec les constructeurs (s'il devait en ajouter un), ce qui malheureusement ne fonctionne pas dans le C++ courant avec des tableaux (autres que les initialiser en valeur). –

+3

La différence principale est vraiment juste le * type * assigné par le système de type. 'x' est de type' char', et 'y' est de type' char [1] '. Je sais que cela me semble indiquer simplement l'évidence, mais c'est vraiment la principale différence. Vous ne pouvez pas passer 'y' à une fonction qui attend un' char' en tant que paramètre, par exemple. Mais finalement, x et y renverront tous les deux la même valeur lorsqu'ils seront passés à l'opérateur 'sizeof', et ils seront probablement représentés exactement de la même manière en mémoire. En outre, 'y' peut se dégrader en un pointeur, ce qui signifie que vous pouvez le passer à quelque chose comme' strcpy', mais vous ne pouvez pas le faire avec 'x' –

11

Si vous avez déjà vu la construction char y[1] en tant que dernier membre d'une structure dans le code de production, il est probable que vous ayez rencontré une instance du struct hack.

Ce court tableau est un remplaçant pour un tableau réel, mais de longueur variable (rappelez-vous qu'avant c99, il n'y avait rien de tel dans la norme c). Le programmeur allouerait toujours de telles structures sur le tas, en veillant à ce que l'allocation soit suffisamment grande pour la taille réelle du tableau qu'il voulait utiliser.

+6

Et si vous voyez le hack struct dans le code C++, vous inquiétez pas ... –

+0

Steve: Sauf si le code C++ doit parler avec le code C. Par exemple le code C++ consommant Win32APIs –

+0

@Billy: bien sûr, si le hack apparaît dans une structure définie par une API C, c'est OK. Je suppose que le hack est toujours "en code C++", en ce sens que l'en-tête devient C++ dès que vous l'incluez dans un programme C++, donc c'est une exception à ma règle. –

3

En plus des différences d'utilisation notées par Steve, le caractère char [1] peut être transmis par ex. template <int N> void f(char(&a)[N]), où char x = '\0'; f(&x); ne correspond pas. Capturer de manière fiable la taille des arguments de tableau est très pratique et rassurant. Cela peut également impliquer quelque chose de différent: soit que la longueur réelle peut être plus longue (comme expliqué par dmckee), ou que le contenu est logiquement une chaîne ASCIIZ (qui se trouve être vide dans ce cas), ou un tableau de caractères (qui arrive à avoir un élément). Si la structure était l'une de plusieurs structures apparentées (par exemple un vecteur mathématique où la taille du tableau était un argument modèle, ou un encodage de la disposition de la mémoire nécessaire pour certaines opérations d'E/S), il est tout à fait possible de similitude avec d'autres champs où les tableaux peuvent être plus grands suggérerait une préférence pour un tableau à un seul caractère, permettant au code de support d'être plus simple et/ou plus universellement applicable.