web-dev-qa-db-fra.com

Que signifie le symbole\0 dans un littéral de chaîne?

Considérons le code suivant:

char str[] = "Hello\0";

Quelle est la longueur du tableau str et avec combien de 0 il se termine?

47
UmmaGumma

sizeof str est 7 - cinq octets pour le texte "Hello", plus le terminateur NUL explicite, plus le terminateur NUL implicite.

strlen(str) est 5 - les cinq octets "Bonjour" uniquement.

La clé ici est que le terminateur nul implicite est toujours ajouté - même si le littéral chaîne se termine juste par \0. Bien sûr, strlen s'arrête juste au premier \0 - il ne peut pas faire la différence.

Il existe une exception à la règle de terminaison NUL implicite: si vous spécifiez explicitement la taille du tableau, la chaîne sera tronquée pour tenir:

char str[6] = "Hello\0"; // strlen(str) = 5, sizeof(str) = 6 (with one NUL)
char str[7] = "Hello\0"; // strlen(str) = 5, sizeof(str) = 7 (with two NULs)
char str[8] = "Hello\0"; // strlen(str) = 5, sizeof(str) = 8 (with three NULs per C99 6.7.8.21)

Ceci est toutefois rarement utile et risque de mal calculer la longueur de la chaîne et de se terminer par une chaîne non terminée. Il est également interdit en C++.

84
bdonlan

La longueur du tableau est 7, le caractère NUL \0 compte toujours comme un caractère et la chaîne se termine toujours par un \0 implicite

Voir ce lien pour voir un exemple de travail

Notez que si vous aviez déclaré str comme char str[6]= "Hello\0";, la longueur serait de 6 car le NUL implicite n'est ajouté que s'il peut tenir (ce qui n'est pas possible dans cet exemple)

§ 6.7.8/p14
Un étalage de Le type de caractère peut être initialisé par un littéral de chaîne de caractères, éventuellement enfermés dans des accolades. Sucessive caractères de la chaîne de caractères littéral (y compris le caractère null final s'il y a de la place ou si le tableau est de taille inconnue) initialiser les éléments du tableau.

Exemples

char str[] = "Hello\0"; /* sizeof == 7, Explicit + Implicit NUL */
char str[5]= "Hello\0"; /* sizeof == 5, str is "Hello" with no NUL (no longer a C-string, just an array of char). This may trigger compiler warning */
char str[6]= "Hello\0"; /* sizeof == 6, Explicit NUL only */
char str[7]= "Hello\0"; /* sizeof == 7, Explicit + Implicit NUL */
char str[8]= "Hello\0"; /* sizeof == 8, Explicit + two Implicit NUL */
10
SiegeX

Frapper mon solo de batterie habituel de JUST TRY IT , voici comment vous pouvez répondre à des questions comme celle-ci à l'avenir:

$ cat junk.c
#include <stdio.h>

char* string = "Hello\0";

int main(int argv, char** argc)
{
    printf("-->%s<--\n", string);
}
$ gcc -S junk.c
$ cat junk.s

... Éliminer les parties inutiles ...

.LC0:
    .string "Hello"
    .string ""

...

.LC1:
    .string "-->%s<--\n"

...

Notez ici comment la chaîne que j'ai utilisée pour printf est simplement "-->%s<---\n" alors que la chaîne globale est en deux parties: "Hello" et "". L'assembleur GNU termine également les chaînes avec un caractère implicite NUL; le fait que la première chaîne (.LC0) se trouve dans ces deux parties indique qu'il existe deux NULs. La chaîne a donc une longueur de 7 octets. Généralement, si vous voulez vraiment savoir ce que fait votre compilateur avec un certain morceau de code, isolez-le dans un exemple factice comme ceci et voyez ce qu'il fait avec -S (pour GNU - MSVC a également un drapeau pour l'assembleur. sortie mais je ne le sais pas au pied levé). Vous en apprendrez beaucoup sur le fonctionnement de votre code (ou ne fonctionnera pas selon le cas) et vous obtiendrez rapidement une réponse garantie à 100% correspondant aux outils et à l'environnement dans lesquels vous travaillez.

5

Plus précisément, je tiens à mentionner une situation dans laquelle vous pouvez confondre.

Quelle est la différence entre "\ 0" et ""?

La réponse est que "\0" représente dans le tableau {0 0} et que "" est {0}.

Parce que "\0" est toujours un littéral de chaîne et qu'il ajoutera également "\0" à la fin de celui-ci. Et "" est vide, mais ajoutez aussi "\0".

Comprendre ceci vous aidera à comprendre "\0" profondément.

4
YongHao Hu

Quelle est la longueur du tableau str et avec combien de 0 il se termine?

Découvrons-le:

int main() {
  char str[] = "Hello\0";
  int length = sizeof str / sizeof str[0];
  // "sizeof array" is the bytes for the whole array (must use a real array, not
  // a pointer), divide by "sizeof array[0]" (sometimes sizeof *array is used)
  // to get the number of items in the array
  printf("array length: %d\n", length);
  printf("last 3 bytes: %02x %02x %02x\n",
         str[length - 3], str[length - 2], str[length - 1]);
  return 0;
}
3
Fred Nurk
char str[]= "Hello\0";

Ce serait 7 octets.

En mémoire ce serait:

48 65 6C 6C 6F 00 00
H  e  l  l  o  \0 \0

Modifier: 

  • Que signifie le symbole\0 dans une chaîne C?
    C'est la "fin" d'une chaîne. Un caractère nul. En mémoire, c'est en fait un zéro. Habituellement, les fonctions qui gèrent les tableaux de caractères recherchent ce caractère, car il s’agit de la fin du message. Je vais mettre un exemple à la fin.

  • Quelle est la longueur de str array? (Répondu avant la partie d'édition)
    7

  • et avec combien de 0 il se termine?
    Votre tableau a deux "espaces" avec zéro; str [5] = str [6] = '\ 0' = 0

Exemple supplémentaire:
Supposons que vous ayez une fonction qui affiche le contenu de ce tableau de texte . Vous pouvez le définir comme suit:

char str[40];

Maintenant, vous pouvez changer le contenu de ce tableau (je n’entrerai pas dans les détails sur la marche à suivre), de sorte qu’il contienne le message: "Ceci est juste un test d’impression" En mémoire, vous devriez avoir quelque chose comme:

54 68 69 73 20 69 73 20 6a 75 73 74 20 61 20 70 72 69 6e 74
69 6e 67 20 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00

Donc, vous imprimez ce tableau de caractères. Et puis vous voulez un nouveau message. Disons juste "Bonjour"

48 65 6c 6c 6f 00 73 20 6a 75 73 74 20 61 20 70 72 69 6e 74
69 6e 67 20 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00

Remarquez le 00 sur str [5]. C'est ainsi que la fonction d'impression saura combien elle doit réellement envoyer, malgré la longitude réelle du vecteur et de l'ensemble du contenu.

0
L. Lopez