'\ 0' et printf () en C

21

Dans un cours d'introduction de C, j'ai appris que tout en stockant les chaînes sont stockées avec un caractère nul \0à la fin de celui-ci. Mais que se passe-t-il si je voulais imprimer une chaîne, disons printf("hello")bien que j'ai trouvé que cela ne se termine pas \0par la déclaration suivante

printf("%d", printf("hello"));

Output: 5

mais cela semble incohérent, pour autant que je sache que les chaînes de type variable sont stockées dans la mémoire principale et je suppose qu'en imprimant quelque chose, elles peuvent également être stockées dans la mémoire principale, alors pourquoi la différence?

Ajay Mishra
la source
1
Outre le fait que votre code manque au moins );, qu'avez-vous l'intention de montrer avec ce code? Comment avez-vous prouvé que cela ne se termine pas par un \0?
glglgl
Et qu'est-ce que la mémoire dans laquelle elle est stockée, y est-elle liée?
Tsakiroglou Fotis
En C, toutes les chaînes littérales sont vraiment des tableaux de caractères, qui incluent le terminateur nul.
Un programmeur mec le
@glglgl Je pense que printf () renvoie le nombre de caractères qu'il est censé imprimer à l'écran.
Ajay Mishra
4
@AjayMishra Oui, et il devrait en effet avoir imprimé 5 caractères. L'octet final 0 n'est pas imprimé à l'écran.
glglgl

Réponses:

13

L'octet nul marque la fin d'une chaîne. Il n'est pas compté dans la longueur de la chaîne et n'est pas imprimé lorsqu'une chaîne est imprimée avec printf. Fondamentalement, l'octet nul indique aux fonctions qui manipulent les chaînes quand s'arrêter.

Là où vous verrez une différence, c'est si vous créez un chartableau initialisé avec une chaîne. L'utilisation de l' sizeofopérateur reflétera la taille du tableau, y compris l'octet nul. Par exemple:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6
dbush
la source
Je pensais que l'histoire serait différente avec printf(). TBH Je ne sais pas comment ça printf()marche.
Ajay Mishra
8

printfrenvoie le nombre de caractères imprimés. '\0'n'est pas imprimé - il signale simplement qu'il n'y a plus de caractères dans cette chaîne. Il n'est pas non plus pris en compte dans la longueur de la chaîne

int main()
{
    char string[] = "hello";

    printf("szieof(string) = %zu, strlen(string) = %zu\n", sizeof(string), strlen(string));
}

https://godbolt.org/z/wYn33e

sizeof(string) = 6, strlen(string) = 5
P J__
la source
6

Votre hypothèse est fausse. Votre chaîne se termine en effet par un \0.

Il contient 5 caractères h, e, l, l, oet le caractère 0.

Ce que l' print()appel "intérieur" génère est le nombre de caractères imprimés, et c'est 5.

glglgl
la source
6

En C, toutes les chaînes littérales sont vraiment des tableaux de caractères, qui incluent le terminateur nul.

Cependant, le terminateur nul n'est pas compté dans la longueur d'une chaîne (littérale ou non) et il n'est pas imprimé. L'impression s'arrête lorsque le terminateur nul est trouvé.

Un mec programmeur
la source
Est-il possible de vérifier cela sans stocker la chaîne dans un tableau?
Ajay Mishra
1
@AjayMishra Eh bien, la chaîne est déjà dans un tableau (comme mentionné) ... Mais s'il n'y avait pas de terminateur nul, alors printfsortirait des limites de la chaîne, et afficherait des caractères "aléatoires" ou "garbage", et retournerait un nombre différent de la longueur de la chaîne. Si vous connaissez déjà la longueur de la chaîne, vous pouvez également vérifier si le caractère de cet index est '\0', ce qui fonctionnera mais est un comportement techniquement indéfini si la taille du tableau n'inclut pas le terminateur (comme dans char arr[5] = "hello";, qui n'ajoutera pas le terminateur au tableau).
Un programmeur mec le
@AjayMishra Oui E. g., Vous pouvez faire char * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }et voir comment cela fonctionne: il montre les lignes avec des index et le contenu de cette ligne. Après l'index 4, il trouve le caractère 0 et rompt la boucle while. Là, vous voyez qu'il y a un caractère 0.
glglgl
6

Toutes les réponses sont vraiment bonnes mais j'aimerais ajouter un autre exemple pour compléter toutes ces

#include <stdio.h>

int main()
{
    char a_char_array[12] = "Hello world";

    printf("%s", a_char_array);
    printf("\n");

    a_char_array[4] = 0; //0 is ASCII for null terminator

    printf("%s", a_char_array);
    printf("\n");

    return 0;
}

Pour ceux qui ne veulent pas essayer ceci sur gdb en ligne, le résultat est:

Bonjour le monde

Enfer

https://linux.die.net/man/3/printf

Est-ce utile pour comprendre ce que fait le terminateur d'échappement? Ce n'est pas une limite pour un tableau de caractères ou une chaîne. C'est le personnage qui dira au gars qui analyse -STOP, (print) analyse jusqu'à ici.

PS: Et si vous analysez et imprimez-le comme un tableau de caractères

for(i=0; i<12; i++)
{
    printf("%c", a_char_array[i]);
}
printf("\n");

vous obtenez:

Monde de l'enfer

où, le blanc après le double l, est le terminateur nul, cependant, en analysant un tableau de caractères, ne sera que la valeur de chaque octet. Si vous effectuez une autre analyse et imprimez la valeur int de chaque octet ("% d%, char_array [i]), vous verrez que (vous obtenez la représentation ASCII code-int) l'espace blanc a une valeur de 0.

Tsakiroglou Fotis
la source
4

Dans la Cfonction printf()retourne le nombre de caractères imprimés, \0est un nullterminateur qui est utilisé pour indiquer la fin de la chaîne en langage c et il n'y a pas de stringtype intégré à partir de c++, cependant la taille de votre tableau doit être au moins supérieure au nombre charsouhaité ranger.

Voici la ref: cpp ref printf ()

un utilisateur
la source
3

Mais que se passe-t-il si je voulais imprimer une chaîne, dites printf ("bonjour") bien que j'ai trouvé que cela ne se termine pas par \ 0 en suivant l'instruction

printf("%d", printf("hello"));

Output: 5

Vous avez tort. Cette instruction ne confirme pas que le littéral de chaîne "hello"ne se termine pas par le caractère zéro de fin '\0'. Cette instruction a confirmé que la fonction printfgénère des éléments d'une chaîne jusqu'à ce que le caractère zéro de fin soit rencontré.

Lorsque vous utilisez un littéral de chaîne comme dans l'instruction ci-dessus, le compilateur crée un tableau de caractères avec la durée de stockage statique qui contient des éléments du littéral de chaîne.

En fait, cette expression

printf("hello")

est traité par le compilateur quelque chose comme ce qui suit

static char string_literal_hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
printf( string_literal_hello );

L'action de la fonction printf dans ce que vous pouvez imaginer de la manière suivante

int printf( const char *string_literal )
{
    int result = 0;

    for ( ; *string_literal != '\0'; ++string_literal )
    {    
        putchar( *string_literal );
        ++result;
    }

    return result;
}

Pour obtenir le nombre de caractères stockés dans la chaîne littérale "bonjour", vous pouvez exécuter le programme suivant

#include <stdio.h>

int main(void) 
{
    char literal[] = "hello";

    printf( "The size of the literal \"%s\" is %zu\n", literal, sizeof( literal ) );

    return 0;
}

La sortie du programme est

The size of the literal "hello" is 6
Vlad de Moscou
la source
0

Vous devez d'abord effacer votre concept. Comme il sera effacé lorsque vous traitez avec un tableau, la commande d'impression que vous utilisez ne fait que compter les caractères placés entre parenthèses. Son nécessaire dans la chaîne de tableau qui se terminera par \ 0

Muhammad Kashif
la source
0

Une chaîne est un vecteur de caractères. Contient la séquence de caractères qui forment la chaîne, suivie de la chaîne de caractères de fin spéciale: '\ 0'

Exemple: char str [10] = {'H', 'e', ​​'l', 'l', 'o', '\ 0'};

Exemple: le vecteur de caractères suivant n'est pas une chaîne car il ne se termine pas par '\ 0'

char str [2] = {'h', 'e'};

Nicola Brogelli
la source
Il n'y a pas de vecteurs en C, je suppose.
Ajay Mishra