J’ai donc un jeu de code simple:
#include int main() { char x[3] = "ABC"; // (*) puts(x); return 0; }
Il retourne une sortie étrange:
ABC¬ a
En utilisant la réponse principale de cette question , j’ai constaté que lorsque j’ai remplacé x[3]
par x[4]
tout se passait bien.
Mais pourquoi? Pourquoi ai-je une sortie étrange sur x[3]
, et pourquoi x[4]
correct?
Puisque vous avez demandé “pourquoi” cela donne ABC -a
, voici une explication: votre caractère char x[3] = "ABC"
ne convient pas aux options de puts
. puts
attend une chaîne terminée par zéro. Cependant, votre x
est fondamentalement:
char x[3] = {'A', 'B', 'C'};
Comme vous le savez, il n’ya aucun moyen d’obtenir la longueur d’un tableau (dynamic):
char * allocate(){ return malloc(rand() + 1); } char * mem = allocate(); // how large is mem??
Il n’y a aucun moyen pour vous de savoir combien de temps cela prend. Cependant, pour imprimer une chaîne qui n’est rien d’autre qu’une séquence continue de caractères en mémoire, une fonction doit savoir quand la chaîne (c’est-à-dire la séquence de caractères) se termine.
C’est pourquoi le code standard américain d’échange d’informations (ASCII) et de nombreux autres jeux de caractères contiennent le caractère null . C’est fondamentalement caractère avec la valeur 0
:
char wrong_abc[3] = {'A', 'B', 'C'}; // when does it end? char correct_abc[4] = {'A', 'B', 'C', 0 }; // oh, there's a zero!
Maintenant, les fonctions telles que les puts
peuvent simplement vérifier 0
:
// Simplified, actual "puts" checks for errors and returns // EOF on error or a non-negative int on succes. void puts(const char * str){ int i = 0; while(str[i] != 0){ putchar(str[i]); i++; } putchar('\n'); }
Et c’est pourquoi tu
0
. L’implémentation de puts
ci-dessus ne trouverait jamais 0
et laisserait accidentellement la mémoire que vous possédez (ou accédez à d’autres données), ce qui conduit généralement à une erreur de segmentation ou à d’autres erreurs (ou pire, ne sont pas détectés pendant une longue période et produisent ensuite des erreurs critiques ). Le comportement réel dans une telle situation est indéfini.
Notez que les littéraux de chaîne (par exemple "ABC"
) ont automatiquement un '\0'
à la fin. En outre, le compilateur est assez intelligent pour déterminer la longueur du littéral pour vous, vous pouvez donc simplement utiliser
char x[] = "ABC";
De cette façon, vous n’avez pas à vous inquiéter si vous changez le littéral plus tard.
Il n’y a pas d’espace pour le \0
. En fait, je m’attendrais à ce que la compilation échoue dans ce cas.
Essayer
char x[4] = "ABC";
Ou, comme l’ a suggéré @Zeta , juste
char x[] = "ABC";
Une chaîne se termine par le caractère null – vous ne lui avez pas alloué d’espace.
Faire
char x[] = "ABC";
et laissez le compilateur faire le travail pour vous!
Votre chaîne doit être terminée par \0
.
Utilisation
char x[] = "ABC";
au lieu.
En utilisant la réponse principale de cette question, j’ai constaté que lorsque j’ai remplacé x [3] par x [4], tout se passait bien.
MAIS POURQUOI? Que se passe-t-il pour que x [3] produise un résultat aussi étrange?
puts()
continue jusqu’à rencontrer un \0
octet final. Donc, si vous n’en fournissez pas à la fin de votre chaîne, il continue à courir derrière votre chaîne jusqu’à ce qu’il trouve un \0
ou se bloque .
Voir les mises () description :
La fonction commence à copier à partir de l’adresse spécifiée (str) jusqu’à atteindre le caractère nul final (‘\ 0’) . Ce caractère nul final n’est pas copié dans le stream.
Chaque fois que vous déclarez une variable chaîne, ajoutez simplement un caractère supplémentaire à ceux dont vous avez besoin pour le caractère de fin '\0'
et tout ira bien.