Dans le code suivant, je copie une chaîne dans un char * Str, de 10 caractères, en utilisant maintenant selon La chaîne source est de 26 caractères longs et j'ai copié 10 caractères, aucun caractère nul n'est placé à la fin de STR. P> mais quand j'imprime le contenu de STR, de commencer De 0 jusqu'à ce que je reçois '\ 0', il se comporte normalement. P> pourquoi? Quand il n'y a pas de "\ 0 'placé à la fin, alors pourquoi la boucle s'arrête-t-elle au bon endroit? P> Ce que je comprends, c'est qu'il devrait donner" défaut de segmentation "ou au moins cela ne devrait pas arrêter Là-bas et continuez à imprimer des valeurs de déchets. p> voici la sortie: p> toute aide sera appréciée. < / p> est-il un moyen approprié de vérifier si une chaîne se termine à "\ 0" ou non? J'ai toujours pensé que la boucle ci-dessus soit le test ultime, mais maintenant, il semble que ce ne soit pas. P> Disons que nous obtenons une chaîne de certaines fonctions développées par d'autres programmeurs. Maintenant, comment saurons-nous que cela se termine au bon endroit avec '\ 0'. Peut-être que ce n'est pas le cas, alors il ira au-delà de la taille réelle jusqu'à ce que nous obtenions une "\ 0". Nous ne pouvons jamais connaître la taille réelle de la chaîne. P> Alors, comment pouvons-nous nous attaquer à une telle situation? P> Toute suggestion? P> P> strncpy () code>. strncpy () code> manuel, "AVERTISSEMENT: S'il n'y a pas d'octet null des notes de SRC SRC, la chaîne placée dans DEST ne sera pas terminée null." Ce qui est exactement Que se passe t-il ici. p>
6 Réponses :
Il arrive juste qu'il y ait un octet nul droit au-delà de la fin du bloc attribué. p>
Très probablement Quoi qu'il en soit, vous ne devriez pas compter sur ce comportement. Vous devez demander ( Il n'y a pas de moyen portable de tester si une chaîne est désignée correctement. Cela peut arriver qu'une fois que vous aurez passé la fin du bloc attribué, votre programme va simplement planter. Ou il peut arriver qu'il y ait un caractère nul quelque part au-delà de la fin du bloc et vous écrasez la mémoire au-delà de la fin du bloc plus tard, lors de la manipulation de la chaîne mal interprétée. P>
Idéalement, vous avez besoin d'une fonction qui voudrait vérifier si une adresse donnée est allouée à vous et em> appartient à la même allocation qu'une autre adresse donnée (peut-être le début du bloc). Ce serait lent et ne vaut pas la peine et il n'y a pas de moyen standard de faire cela. P>
En d'autres termes, si vous rencontrez une chaîne destinée à être terminée de nulliser mais que vous n'êtes vraiment pas vêtu de gros temps - votre programme traversera un comportement non défini. P> MALLOC () CODE> alloue plus de mémoire et met également appelé valeurs de garde em> qui contiennent des octets nulles ou que certaines métadonnées doivent être utilisées par Gratuit () Code> plus tard et cette métadonnée contient un octet nulle à cette position. P>
MALLOC () CODE>) Un octet de plus pour le caractère NULL afin que l'emplacement de caractère null soit également légalement alloué à vous. P>
Oui, il se trouve être un octet nul à la fin de la chaîne. Si vous essayez différentes tailles, vous obtiendrez la sortie Bad i>.
Donc, il n'y a pas de moyen standard de vérifier si une chaîne est null terminée ou non. C'est une mauvaise nouvelle. Je pense que tous les programmeurs travaillant sur la demande doivent être d'accord sur une norme. Comme les trois premiers caractères d'un pointeur indiquera à sa taille et à partir de quatrième que la chaîne réelle commencera.
@Andrew: Alors, que se passe-t-il si ces trois octets au début de la chaîne sont faux? Ensuite aussi, votre programme se bloquera et brûlera. Le point ici est que si les structures de données sont incohérentes, vous aurez des problèmes, et c'est très difficile (lire «très dur» comme «logiquement impossible») de faire quelque chose à ce sujet.
@Andrew: Il y a un accord. Il indique que la chaîne contient un octet supplémentaire qui contient un terminateur nul.
Pourquoi ça marche? P> blockQuote>
La mémoire que vous allouez se produit pour avoir un
'\ 0' code> octet au bon endroit. (Par exemple, si vous utilisez Visual C ++ en mode de débogage, le gestionnaire de tas Zeros a alloué la mémoire avant de la remettre à votre programme. Mais cela pourrait aussi bien être une chance pure.) P>Y a-t-il une bonne façon de vérifier si une chaîne se termine à
'\ 0' code> ou non? p> blockQuote>Non. Vous avez besoin de vos chaînes pour être terminées par zéro (qui correspond à ce que les fonctions de traitement des chaînes STD LIB attendent) ou vous devez transporter leur longueur dans une variable supplémentaire. Si vous n'avez aucun des deux, vous avez un bogue. P>
Maintenant, comment saurons-nous que certaines chaînes de certaines fonctions développées par un autre programmeur se termine à un endroit correct avec
'\ 0' code>. Peut-être que ce n'est pas le cas, alors il ira au-delà de la taille réelle jusqu'à ce que nous obtenions du'\ 0' code>. Nous ne pouvons jamais connaître la taille réelle de la chaîne. P>Alors, comment pouvons-nous aborder une telle situation? p> blockQuote>
Vous ne pouvez pas. Si l'autre fonction laviste si mal, vous êtes bousillé ce mauvais. P>
À propos de la mémoire de mise à zéro du gestionnaire de tas: le compilateur Microsoft ne peut pas zéro Memory (n de débogage ou de libération). Lorsque vous utilisez le tas de débogage, le runtime MSVC remplira la mémoire allouée avec 0xCD octets, pas zéro. Le remplissage de «ordures» plutôt que de nettoyer la mémoire est généralement plus efficace pour trouver des problèmes. En outre, une partie de la mémoire avant et après l'allotation sera remplie de valeurs 0xfd. Voir Stackoverflow.com/Questtions/370195/...
@Michaeal: Pour tout ce que je sais, vous pourriez avoir raison. Mais toujours, ISTR ayant lu à nouveau et encore que les variables ne soient pas à zéro sont une cause typique de la libération des versions s'écraser pendant que les versions de débogage fonctionnent en VC.
Sharpoth a expliqué la cause probable du comportement, donc je ne vais pas répéter cela.
Lorsque vous allouez des tampons, je toujours em> sur-allouer par un octet, comme celui-ci: p>
Hein, "Tailleof (Char) - (taille + 1)"? Moins?
Nous pouvons également faire cette mémoire (DEST, 0, TAILLE); Strncpy (Dest, Source, Taille -1); De cette façon, le dernier octet aura un zéro.
Cela devrait être * - fois. Nouveau clavier :)
Oui, j'utilise souvent Memset. Mais je trouve la mission directe plus claire. Et si vous utilisez Strncpy (), il couvre tout espace inutilisé avec 0s de toute façon.
Bien que ce ne soit pas une mauvaise idée en soi, une solution beaucoup plus simple est de ne jamais utiliser les versions non liées des fonctions de chaîne. Au lieu d'assurer manuellement la résiliation nulle, utilisez uniquement des fonctions qui prennent une limite supérieure et garantissent le retour d'une chaîne C valide (c'est une sorte de honte Strncpy n'offre pas ce Gaureree). Il existe généralement des versions plus sécurisées de Strncpy, telles que Strlcpy sur les BSD et StrncPy_s sous Windows.
Combinée à une charrette d'affectation excessive et de la fixation à NULL, STRNCOPY garantit cela. C'est pourquoi je le fais.
Quant à votre édition, je pense que être pédants aidera à élucider des problèmes. p>
en C Il n'existe pas de chaîne. Il existe un concept d'une "chaîne C" qui est ce que la bibliothèque standard C fonctionne avec laquelle il est défini comme rien de plus qu'une séquence de caractères terminée Nul, il n'y a donc vraiment pas une chose une "chaîne non nulle terminée "Dans C. Votre question est donc mieux formulée comme" Comment puis-je déterminer si un tampon de caractère arbitraire est une chaîne C valide? " ou "Comment puis-je déterminer si la chaîne que j'ai trouvée est la chaîne prévue" p>
La réponse à la première question, malheureusement, est de numériser de manière linéairement le tampon jusqu'à ce que vous rencontriez un octet nul comme vous le faites. Cela vous donnera la longueur de la chaîne C. P>
La deuxième question n'a pas de réponse facile. En raison du fait que C n'a pas de type de chaîne réelle avec des métadonnées de longueur (ou la possibilité de transporter la taille des tableaux entre les appels de fonction), il n'y a pas de réel moyen de déterminer si la longueur de la chaîne que nous avons déterminée ci-dessus est la longueur de la chaîne prévue. Il serait peut-être évident que si nous commençons à voir des segfault dans le programme ou «ordures» dans la sortie, mais en général, nous sommes bloqués en faisant des opérations de chaîne en balayant jusqu'à ce que le premier octet nul (généralement avec une longueur supérieure sur une longueur de chaîne de manière à éviter de désordre. Erreurs de dépassement de tampon) p>
Vous avez de la chance d'avoir zéro au-delà de la région allouée d'espace. P>
Essayez ce code sur toutes les autres plates-formes et vous verrez que cela pourrait ne pas se comporter de la même manière. P>
Je pense que la réponse de Sharpoth a raison. Il y a plus d'espace alloué. Je modifie le programme comme suit: la sortie est p> mon système d'exploitation est debian Squeeze / SID. P> p>
Tailleof (Char) est TOUJOURS i> 1 !!
@PAX: True, mais voici une discussion de celle-ci: Stackoverflow.com/Questtions/1011806/...
STRNCMP prend le nombre de caractères, pas la taille de la chaîne cependant, il est donc faux de l'utiliser là-bas.
@Pete Kirkham: Qu'est-ce que je comprends du manuel, c'est que Strncpy () copie n octets de SRC dans Dests. Je n'ai pas l'intention de donner la taille de la chaîne. C'est une façon, j'ai pensé à écraser la résiliation null.