strtok segmentation fault
Je suis en train d'essayer de comprendre pourquoi l'extrait de code suivant donne une erreur de segmentation:
void tokenize(char* line)
{
char* cmd = strtok(line," ");
while (cmd != NULL)
{
printf ("%s\n",cmd);
cmd = strtok(NULL, " ");
}
}
int main(void)
{
tokenize("this is a test");
}
Je sais que strtok() ne le fait pas marquer sur les littéraux de chaîne, mais dans ce cas, line
points directement à la chaîne "this is a test"
qui est à l'intérieur d'un tableau de char
. Est-il de jetons line
sans la copier dans un tableau?
Mec - "ceci est un test" est un LITTÉRAL de CHAÎNE. C'est un LECTURE SEULE "tableau de char". Vous pourriez même obtenir loin de tenter de modifier sans s'écraser sur certaines plates-formes. Mais il est certainement un pas-à-pas sur AUCUN plate-forme 🙂
OriginalL'auteur user1162954 | 2012-01-22
Vous devez vous connecter pour publier un commentaire.
Le problème, c'est que vous tentez de modifier une chaîne littérale. En procédant ainsi, votre programme du comportement indéfini.
Dire que vous n'êtes pas autorisé à modifier une chaîne de caractères littérale est une simplification excessive. Dire que les littéraux de chaîne sont
const
est incorrect; ils ne sont pas.AVERTISSEMENT : Digression suit.
La chaîne littérale
"this is a test"
est une expression de typechar[15]
(14 pour la longueur, plus 1 pour la résiliation de'\0'
). Dans la plupart des contextes, y compris celui-ci, une telle expression est implicitement converti en un pointeur vers le premier élément du tableau, de typechar*
.Le comportement de tenter de modifier le tableau visé par un littéral de chaîne n'est pas défini-pas parce que c'est
const
(n'est pas), mais parce que le C standard spécifiquement dit que c'est pas défini.Certains compilateurs peuvent vous permettre de sortir avec cette. Votre code peut effectivement modifier le tableau statique correspondant à la lettre (ce qui pourrait causer une grande confusion plus tard).
Plus les compilateurs modernes, cependant, va stocker le tableau dans la mémoire en lecture seule-pas physique ROM, mais dans une région de la mémoire qui est protégée contre toute modification par le système de mémoire virtuelle. Le résultat de la tentative de modifier une telle mémoire est généralement une erreur de segmentation et un plantage du programme.
Alors pourquoi ne sont pas littéraux de chaîne
const
? Depuis que vous avez vraiment ne devriez pas essayer de les modifier, il serait certainement faire sens -- et C++ permet de faire des littéraux de chaîneconst
. La raison en est historique. Leconst
mot-clé qui n'existait pas auparavant, il a été introduit en 1989 par le C ANSI standard (même s'il a probablement été mis en œuvre par certains compilateurs avant). Donc un pré-ANSI programme pourrait ressembler à ceci:Il n'y a aucun moyen de faire respecter le fait que
print_string
n'est pas autorisé à modifier la chaîne de caractères pointée pars
. Faire des littéraux de chaîneconst
en C ANSI aurait brisé le code existant, dont le C ANSI comité essayé très dur pour éviter de le faire. Il n'a pas été une bonne occasion depuis de faire un tel changement de la langue. (Les concepteurs du C++, pour la plupart Bjarne Stroustrup, n'est-ce pas aussi préoccupé par la compatibilité ascendante avec les C.)Serait la downvoter soin d'expliquer?
OriginalL'auteur
Comme vous l'avez dit, vous ne pouvez pas modifier une chaîne littérale, qui est ce que
strtok
. Que vous avez à faireCela crée le tableau
str
et initialise avecthis is a test\0
, et passe un pointeur àtokenize
.OriginalL'auteur
Il y a une très bonne raison qu'en essayant de marquer une constante de compilation de la chaîne va provoquer une erreur de segmentation: la constante de chaîne est en read-only memory.
Le compilateur C cuit constante à la compilation des chaînes dans le fichier exécutable, et le chargement du système d'exploitation en mémoire en lecture seule (.rodata dans un *nix ELFE de fichier). Depuis cette mémoire est en lecture seule, et depuis strtok écrit dans la chaîne de caractères que vous passez, vous obtenez une erreur de segmentation pour l'écriture dans la mémoire en lecture seule.
OriginalL'auteur
Je suis sûr que vous aurez battu à ce sujet... mais "strtok()" est intrinsèquement dangereuses et sujettes à des choses comme des violations d'accès.
Ici, la réponse est presque certainement l'aide d'une chaîne constante.
Essayez plutôt ceci:
OriginalL'auteur
Strok modifie son premier argument pour marquer. Par conséquent, vous ne pouvez pas passer une chaîne littérale, comme il est de type
const char *
et ne peut pas être modifié, d'où le comportement indéfini. Vous devez copier le littéral de chaîne dans un tableau de char qui peuvent être modifiés.OriginalL'auteur
Quel point êtes-vous essayer de faire par votre "...est à l'intérieur d'un tableau de
char
" remarque?Le fait que
"this is a test"
est à l'intérieur d'un tableau dechar
ne change rien du tout. Il est encore un littéral de chaîne (tous les littéraux de chaîne sont non modifiables, des tableaux de char). Votrestrtok
tente encore de marquer un littéral de chaîne. C'est pourquoi il se bloque.OriginalL'auteur
Je viens de toucher la Segmentation Fault erreur d'essayer d'utiliser printf pour imprimer le jeton (
cmd
dans votre cas), après c'est devenu NUL.OriginalL'auteur