2017-07-21 2 views
0

J'essayais de comprendre comment une chaîne avec une taille connue peut être remplie avec des caractères uniques. Ensuite, j'ai écrit ce code simple pour un plus gros problème que j'ai (remplissage dynamique d'une chaîne de taille inconnue) . Quand j'ai essayé de compiler et d'exécuter ce code, j'ai rencontré un problème dont la sortie avait un symbole de coeur! et je ne sais pas d'où ça vient.Pourquoi la fonction puts() me donne-t-elle un symbole de coeur?

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int i; 
    char str[3]; 
    for(i=0;i<=2;i++){ 
     str[i]=getc(stdin); 
    } 
    puts(str); 
    return 0; 
} 

Merci.

+3

En C 'chaînes de char' sont vraiment appelés *** * null fin ** * chaînes d'octets *. Cette partie "nulle terminée" est importante. Si vous ne l'avez pas dans une chaîne, alors toute la fonction de chaîne sortira des limites dans sa recherche, et vous aurez * un comportement non défini * qui rendra votre programme * mal formé * et invalide. –

+0

@Some programmeur dude_Merci. Pourquoi ne pas ignorer l'entrée supplémentaire? Je sais que les index sont 0,1,2 et l'index-2 est nul. Si j'introduis la pile pourquoi ça ne passe pas ack? –

+2

Mais vous * ne * terminez pas la chaîne dans 'str', vous lisez trois caractères et les placez dans le tableau. Si vous voulez lire trois caractères, le tableau doit être de * quatre * caractères, le dernier élément étant le caractère de terminaison (que vous devez explicitement initialiser comme tel). –

Répondre

3

Les C strings sont des séquences de caractères terminées par null character (c'est-à-dire le caractère avec le code 0). Il peut être exprimé comme '\0', '\x0' ou simplement 0.

Votre code remplit str avec trois caractères mais ne produit pas le terminateur null. Par conséquent, puts() imprime les caractères qu'il trouve dans la mémoire jusqu'à ce qu'il atteigne le premier caractère null. Votre code expose Undefined Behaviour. Il peut tout faire et ce n'est pas sa faute.

Pour le fixer, vous devez vous assurer que la chaîne se termine par le caractère de fin null:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int i; 
    // Make room for 3 useful chars and the null terminator 
    char str[4]; 
    // Read three chars 
    for(i = 0; i < 3; i ++) { 
     str[i] = getc(stdin); 
    } 
    // Add the null terminator for strings 
    str[3] = 0; 

    puts(str); 
    return 0; 
} 

Mise à jour

Comme @JeremyP note dans un commentaire, si le fichier que vous lisez de (stdin) se termine avant que le code ne lise 3 caractères, fgetc() renverra EOF (fin du fichier) caractères qui sont aussi des caractères non imprimables drôles qui vous fait vous demander d'où ils viennent.

La bonne façon d'écrire ce code est de vérifier si le fichier d'entrée a atteint son EOF (feof()) avant d'y lire:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int i; 
    // Make room for 3 useful chars and the null terminator 
    char str[4]; 
    // Read at most three chars 
    for(i = 0; i < 3 && !feof(stdin); i ++) { 
     str[i] = getc(stdin); 
    } 
    // Add the null terminator for strings 
    str[i] = 0; 

    puts(str); 
    return 0; 
} 
+0

Et waht si je n'apporte pas 'str [3] = 0' dans mon code? –

+0

Si vous n'ajoutez pas 'str [3] = 0;' alors vous êtes dans la même situation qu'avant. Vous avez 3 caractères définis par 'getc()' et le quatrième est ce qui se passe en mémoire lorsque le code est exécuté; un reste d'un autre code exécuté auparavant. 'str' est une variable locale; il n'est initialisé avec rien quand il est alloué. – axiac

+0

Votre code est toujours incorrect. 'getc()' renvoie 'int' pour qu'il puisse retourner' EOF' quand la fin du fichier est rencontrée. En l'état actuel, si le fichier est plus court que trois caractères, le tampon sera rempli avec des caractères '(char) EOF', probablement' 0xff'. – JeremyP

0

Les chaînes dans c doivent être terminées par un caractère nul; il se peut donc que vous ayez oublié d'ajouter un caractère '\0' à la fin de str. La raison pour laquelle le symbole du coeur apparaît est que quand puts() essaie d'écrire une chaîne, il continue à lire le caractère suivant en mémoire jusqu'à ce qu'il atteigne un terminateur nul, '\0'. Comme il n'en rencontre pas un, il continue de lire dans la mémoire et arrive à trouver le symbole du cœur que je devinerais. J'espère que cela t'aides.

+1

Merci mon cher Nicholas. –

+0

_il pourrait être que vous avez oublié d'ajouter un '\ 0', non, ce n'est pas _il pourrait être, il a réellement oublié d'ajouter le caractère '\ 0 '. –

+0

@MichaelWalz, j'essayais juste d'être poli. –