2010-04-07 3 views
0

Je reçois une erreur de segmentation lors de l'utilisation de la notation strncpy et (pointer-to-struct) -> (membre):Pourquoi ai-je une erreur de segmentation lors de l'utilisation de strncpy?

J'ai simplifié mon code. J'initialise une structure et place tous ses jetons sur une chaîne vide. Puis a déclare un pointeur sur une structure et lui assigne l'adresse de la structure.

Je passe le pointeur sur une fonction. Je peux imprimer le contenu de la structure au début de la fonction, mais si j'essaie d'utiliser le tp -> mnémonique dans une fonction strncpy, je me retrouve en erreur. Quelqu'un peut-il me dire ce que je fais mal? J'ai utilisé des instructions printf pour confirmer que le code s'arrête définitivement à la fonction strncpy.

Répondre

-3

Vous pouvez utiliser la variable tp. Si vous ne faites pas de malloc, il n'y a aucune garantie que la mémoire est réellement la vôtre. Ne pas oublier de libérer la mémoire quand vous avez terminé.

+0

Je ne comprends pas pourquoi je voudrais malloc la variable tp. C'est un pointeur qui pointe vers une mémoire qui a déjà été allouée à la structure du jeton. Si je malloc, cela va allouer une nouvelle mémoire qui n'est pas la structure des jetons, n'est-ce pas? Et je ne veux pas ça. – Joe

+2

Vous vous êtes trompé sur la propriété de la mémoire référencée par "tp" dans l'exemple de code. C'est l'adresse d'une structure qui a été déclarée sur la pile. Il est parfaitement légitime d'utiliser un pointeur comme indiqué, jusqu'à ce que la structure référencée soit hors de portée. À ce stade, la mémoire est libérée et il n'est plus sûr de le référencer. Le bug dans le code d'OP est ailleurs (voir ma réponse). –

+0

-1: Cela n'a absolument rien à voir avec son problème. – rampion

7

suite de la ligne

tokens.mnem = "load" 

attribue mnem à l'adresse du littéral de chaîne, qui est généralement situé en lecture seule segment de données, en changeant si cette mémoire avec strncpy() ou toute autre fonction échouera.

9

Le problème est que tp-> mnem pointe vers un littéral de chaîne, qui est généralement alloué dans un segment de mémoire en lecture seule. Par conséquent, il est illégal de l'écraser. Très probablement ce que vous devez faire est plutôt quelque chose comme ceci:

Tokens tokens; 
tokens.label = ""; 
tokens.mnem = strdup("load"); 
tokens.operand = ""; 

Cela vous donnera un bloc de mémoire alloué dynamiquement pour MNEM, que vous pouvez ensuite écrire en autant que vous le souhaitez. Bien sûr, vous avez aussi quelques autres problèmes: d'abord, vous devrez vous rappeler de libérer cette mémoire avec free plus tard; Deuxièmement, vous devez connaître la taille du tampon que vous avez allouée afin de ne pas l'écraser.

Si vous savez que le contenu de mnem ne dépassera jamais 4 octets, alors vous pourriez plutôt changer votre déclaration de structure comme ceci:

typedef struct tok { 
    char* label; 
    char mnem[5]; // note: +1 byte for a NULL terminator 
    char* operand; 
}Tokens; 

Ensuite, vous auriez lsinitialisez comme ceci:

Tokens tokens; 
tokens.label = ""; 
strcpy(tokens.mnem, "load"); 
tokens.operand = ""; 

Cela vous libère de la responsabilité de la gestion de la mémoire pour mnem, bien que vous ayez encore quelques risques de dépasser votre mémoire tampon.

+1

Si vous voulez traiter le mnem comme une chaîne, vous devez augmenter le caractère d'un caractère et vous assurer qu'il est nul. Sinon, vous pourriez trouver les autres champs et gunk ajoutés dans le sprintf. –

+0

@Ian G: bon point, j'ai mis à jour ma réponse pour refléter cette suggestion. –

2

Vous appelez strncpy() sans avoir alloué l'espace tampon, tout comme Shadow dit.

La chaîne littérale "load" dans laquelle vous définissez le membre mnem dans l'initialiseur n'est pas écrasable.

Si vous souhaitez pouvoir modifier la chaîne stockée et que la taille est raisonnable, il peut être plus simple de simplement modifier la déclaration du champ struct en char mnem[5];.

En outre, s'il vous plaît noter que strncpy() a une sémantique assez étrange. Vérifiez si vous avez strlcpy(); c'est une meilleure fonction.

3

Le problème est que vous avez affecté des littéraux de chaîne aux membres de votre structure Tokens et que vous essayez d'écraser cette mémoire (en particulier, le champ mnem) dans tokenise.

La plupart des systèmes d'exploitation modernes alloueront de la mémoire pour les chaînes littérales à partir d'une section spéciale en lecture seule de l'espace d'adressage de votre programme. Si vous essayez d'écrire dans cette mémoire, votre programme mourra avec un segfault.

C'est pourquoi le type d'un littéral de chaîne est const char *, et non char *. Votre compilateur devrait vous avertir lorsque vous essayez de les affecter aux champs tokenise. Si vous souhaitez réécrire la mémoire ultérieurement, vous devez allouer dynamiquement la mémoire à l'aide de malloc ou remplacer les membres de la structure Tokens par des tableaux de longueur fixe, puis copier la valeur initiale dans la mémoire allouée. Bien sûr, si vous allouez de la mémoire de manière dynamique, vous devrez également l'utiliser plus tard.

2

Vous obtenez une erreur de segmentation parce que cette ligne:

strncpy(tp -> mnem, line, 4); 

tente de copier quatre personnages de « ligne » dans un emplacement occupé par une chaîne de caractères qui lui sont assignées ici:

tokens.mnem = "load"; 

Le littéral de chaîne est stocké dans une partie de texte spéciale de votre programme et ne peut pas être modifié.

Ce que vous devez faire est d'allouer un tampon de votre propre dans lequel la chaîne sera copié:

tokens.mnem = (char*) malloc (bufferSize); 

et libérez le tampon lorsque vous avez terminé de l'utiliser.

0

Cette ligne est sujette à caution:

strncpy(tp -> mnem, line, 4); 

Vous comptez sur une fonction qui renvoie un pointeur vers la mémoire non alloué. Le retour de *tokenise() est indéfini. Son renvoi un pointeur vers la mémoire qui pourrait contenir toutes sortes de choses, et que vous n'avez pas la permission de modifier.

si doit retourner un pointeur alloué.

Questions connexes