6
votes

Défaut de la segmentation avant / pendant la déclaration de retour

Je imprime la valeur que je retourne juste avant ma déclaration de retour et indiquez à mon code d'imprimer la valeur renvoyée juste après l'appel de la fonction. Cependant, je reçois une faute de segmentation après ma première instruction d'impression et avant ma seconde (également intéressante à noter, cela se produit toujours à la troisième fois que la fonction est appelée; jamais le premier ou le deuxième, jamais, jamais le quatrième ou la deuxième, jamais. J'ai essayé d'imprimer toutes les données que je travaille pour voir si le reste de mon code faisait quelque chose, cela ne devrait peut-être pas, mais mes données jusqu'à ce point vont bien. Voici la fonction:

hPos = findHydrogen((&aminoAcid[i]), nPos, diff, totRead);
printf("%d\n", hPos);


13 commentaires

Que se passe-t-il si je == numbonds et aucun "h" est trouvé?


Vous avez des fuites de mémoire dans ce code.


Je l'avais dit à l'origine de sortir de simplement quitter le code (avec une sortie (7); déclaration) Si aucun "H" n'a été trouvé comme ça signifierais quelque chose de mal avec mes données ailleurs, mais comme je ne semblais jamais courir dans ce problème , J'ai enlevé cette ligne.


Pourriez-vous nous donner la ligne qui cause cette faute de segmentation? Exécutez votre programme dans un débogueur (GDB par exemple) et cela vous donnera plus d'informations sur l'état de la pile / programme au moment de l'accident.


@Franci Penov: Où est-ce que j'ai les fuites de mémoire? Je suis assez confiant que je libère tous les indicateurs ... ai-je manqué une ou plusieurs?


Cette fonction est trop complexe.


@Daniel pas vraiment, ça fait un tas de choses inutiles ...


@ wolfpack88 cette mémoire de fuite: liaisons = (int *) malloc (taille de (int) * numbonds); BONDS = ATOMES [NPOS] .BONDS; Vous appelez MALLOC, il vous donne un pointeur à une mémoire, vous définissez des obligations comme ce pointeur, puis vous définissez des obligations à pointer sur autre chose que vous avez maintenant perdu le pointeur MALLOC vous a donné. On dirait que vous essayiez de faire une copie, mais vous n'avez pas besoin de ne jamais changer d'obligations afin que vous puissiez simplement laisser tomber le malloc. En fait, vous pouvez laisser tomber chaque MALLOC et tout libre dans le code et changer essentiellement rien.


Changement de style petit que vous pouvez faire: (* amino) .numatoms peut être écrit comme amino-> numatoms . Rend le code plus clair et signifie la même chose.


@ spudd86 Je ne l'ai pas lu, j'ai dit que c'était trop complexe juste en regardant sa mise en page :)


@Daniel: hein? La disposition? C'est assez court, simple et seulement deux niveaux d'indentation sans autre, qu'est-ce qui ne va pas avec ça? Le seul signe alarmant que je vois est que le retour à la fin est dans le deuxième niveau d'indentation ...


@Secure: Beaucoup de variables, deux pour les boucles (une avec des supports, un sans eux), plus de 15 lignes, un retour à l'intérieur du second pour la boucle. Si l'auteur a une faute de segmentation qu'il ne peut pas clouer, c'est pour une raison quelconque.


@Daniel Yea Mais la plupart d'entre eux ne font que ombrer les choses à partir de la struct, 15 lignes sont terriblement courtes et "point de sortie simple" peut souvent rendre le code plus difficile à lire car il ajoute de la complexité au flux de contrôle, c'est bien si vous pouvez le faire Il est donc réellement plus simple que plusieurs retours ... mais sinon, cela ne vaut pas la peine de faire, comme pour le problème de Wolfpack88; Il ne sait tout simplement pas assez bien et je pense que le vrai problème n'est même pas dans ce code, car il semble que cela devrait fonctionner très bien; mais il devrait ajouter une sorte d'affirmation ou à la fin de "pas atteint"


10 Réponses :


11
votes

Défaut de segmentation pendant que le retour est normalement une indication d'une pile mangue.


3 commentaires

Je ne suis pas tout à fait sûr de ce qui aurait causé ceci ... Pourriez-vous par hasard, donnez-vous un exemple de ce que vous voulez dire pour que je puisse le rechercher dans mon propre code? Merci pour la réponse de toute façon.


En règle générale, vous écririez après la limite de certaines variables sur la pile. Les chaînes sont notoires pour cela, mais cela pourrait être un autre type de tableau, ou une copie de structure ou memcpy () type d'opération.


-1 Pour une réponse trop générique sans tenter d'analyser réellement le code. -1 Pour une mauvaise conjecture - du code, le Segfault ressemble davantage à l'accès à la mémoire de tas déjà libérée et à un problème de corruption de pile.



3
votes

On dirait que vous utilisez des déclarations d'impression pour déboguer des défauts de segmentation: un grand non-non en c.

Le problème est que le stdouté est tamponné sur la plupart des systèmes, ce qui signifie que la défaillance de la segmentation est réellement survenue plus tard que vous ne le pensez. Il est impossible de déterminer de manière fiable lorsque votre programme est SEGFaulting à l'aide de PrintF.

Au lieu de cela, vous devez utiliser un débogueur comme GDB, qui vous indiquera la ligne de code exacte qui cause la défaillance de la segmentation.

Si vous ne savez pas comment utiliser GDB, voici un tutoriel rapide que j'ai trouvé par Google'ing: http://www.cs.cmu.edu/~gilpin/Tutorial/


3 commentaires

Vous pouvez généralement vous éloigner de déboguer en impression si vous vous souvenez de terminer votre impression avec un \ N ou de faire une affleurement () après des impressions de débogage. Je sais que ce n'est pas la meilleure façon de le faire, mais dans certains cas, il est approprié.


Impression sur starr fonctionne mieux (utilisez fprintf (stardr, ...); plutôt que printf (...); ), puisque c'est vraiment ce que stardr est pour. Un vrai débogueur est meilleur, bien sûr.


@David a les deux utilisations ... Si vous avez besoin de voir une longue séquence de choses extraites de cette information d'un débogueur peut être douloureuse (extra-spéciale douloureuse si c'est une interface graphique ...)



8
votes

Il n'est pas facile de deviner où l'erreur provient de ce code (il y a un potentiel de bogue dans à peu près toutes les lignes de code ici) - Vous avez probablement un dépassement tampon quelque part, cependant, si vous êtes sur un * NIX, courez Votre programme sous Valgrind , vous devriez être capable de trouver l'erreur plutôt rapidement.

Ces lignes ont l'air étrange:

atoms = (struct Atom *) malloc(sizeof(struct Atom) * numAtoms);
atoms = (*amino).atoms;


1 commentaires

"Il y a un potentiel de bogue dans à peu près toutes les lignes de code ici" - dur. vrai, mais dur. :-)



4
votes

Il y a beaucoup de choses mal ici.

La première chose que je remarque, c'est que vous fuyez la mémoire (vous allouez une mémoire à (struct atom *) Malloc (Tailleof (Struct Atom) * Numatoms) , puis écrasez le pointeur avec le pointeur dans la structure amino); Vous faites la même chose avec (int *) malloc (tailleof (int) * numbonds); .

second, vous n'êtes pas limité: vérifier l'expression des obligations [i] - Totread .

Troisième, et je pense que c'est là que vous écrivez, vous écrasez votre pointeur d'atomes ici: Atoms = (struct atome *) MALLOC (Tailleof (Struct Atom)); libre (atomes); qui laisse des atomes pointant vers une mémoire invalide.


0 commentaires

3
votes

Ceci est étrange:

atoms[bonds[i] - totRead].type[0] == 'H'


4 commentaires

Eh bien, le pointeur pointe actuellement des données utilisées dans un autre tableau. Je ne veux pas avoir un pointeur supplémentaire pointant vers les mêmes données, je n'ai donc que quelque chose d'autre, puis libérez-le pour éviter les fuites de mémoire. Comme je suis un programmeur relativement nouveau, je ne suis pas sûr que c'est une bonne pratique, mais cela semblait être une bonne idée à l'époque.


Lucas a un point correct. Il peut (presque *) ne jamais être correct d'effectuer un Malloc () et libérer la même mémoire dans la déclaration immédiatement suivante. De lire votre code, il est évident que vous devriez être libre () - votre mémoire avant de réutiliser le pointeur de la mémoire nouvellement attribuée.


@ Wolfpack88: Je ne suis pas sûr de vous comprendre. Si vous ne voulez pas que votre pointeur pointe dans une autre mémoire, le pointe sur null , mais je ne pense pas que c'est ce que vous voulez ici.


@ wolfpack88: vous n'avez réellement besoin de définir atomes ou ou sur quelque chose lorsque vous avez terminé les utiliser - ce sont des variables locales, arrêtez-les simplement de les utiliser lorsque vous ne veulent plus faire référence aux tableaux qui appartiennent à une autre structure. Débarrassez-vous de tous les appels vers MALLOC () et GRATUIT () Dans la fonction - Ils ne font rien d'utile et provoquent une confusion (ainsi que la source de la source de Quelques fuites de mémoire qui n'ont rien à voir avec le Segfault).



5
votes

Editer Eh bien, vous fuiez la mémoire à gauche et à droite, mais pas tout à fait de la façon dont je pensais. Séquence fixe ci-dessous:

Spécifiquement, lorsque vous faites: P>

atoms = (*amino).atoms; // delete 1, 3, 4 entirely and just read directly from the structure


2 commentaires

Je ne pense pas que les appels libres () sont le problème (bien qu'ils confondent le problème). L'appel free () est en cours d'exécution après Atom est défini sur le résultat d'un autre (inutile) malloc () , donc il libère la mémoire Retourné d'un MALLOC () appel. Cependant, tous les appels vers MALLOC () et GRATUIT () dans la fonction semble être inutile.


Je pense que tu as raison. J'ai édité mon message pour indiquer que la mémoire fuit sans prétendre que les appels gratuits sont le vrai problème.



4
votes

Voici une petite réécriture de parties de votre code pour démontrer les fuites de mémoire: xxx

Il y a aussi une chance que l'énoncé liens [i] - Totread peut être hors du atomes [] limites, qui pourrait être le segfault.


0 commentaires

1
votes

Où vous avez écrit:

fprintf(stderr, "Program ran to point A.\nPress return.\n");
fflush(stderr); /* Force the output */
fflush(stdin);  /* Discard previously-typed keyboard input */
fgetc(stdin);   /* Await new input */
fflush(stdin);  /* Discard unprocessed input */


3 commentaires

non le libre est toujours appelé avec la mémoire allouée sur la ligne auparavant, le problème de l'OP est qu'ils ne savent pas réellement comment craine C


@ spudd86 c'est exactement ce que j'ai écrit, comment allez-vous si confus? Le problème est qu'elles écrivent alors à la mémoire pointée par le même pointeur qu'ils viennent de libérer.


Nope, ils retournent juste après la libération, donc aucune références pendlantes (cela va comme cet atomes = malloc; atomes = amino-> Atomes; atomes = malloc; libres (atomes); donc ils finissent par fuite de taille de taille de (atome) * Numatoms bytes mais Don 'T libre tout ce qui ne devrait pas être libre



1
votes

Avez-vous un #include dans le fichier? Je me demande si vous recevez un appel à printf () qui utilise une déclaration implicite de printf () et peut donc utiliser la mauvaise convention d'appel.

Quel est le compilateur / plate-forme que vous utilisez? Avez-vous des avertissements de la construction?


0 commentaires