J'essaie actuellement d'analyser une chaîne dans un tableau de chaînes.
Jusqu'à présent, je crois actuellement que j'ai réussi à fractionné la chaîne en insérant Cependant, lorsque j'essaie de libérer la matrice de cordes plus tard, certains de mes mots ont la même adresse d'octet et, donc, lorsque j'essaie de libérer l'un d'entre eux, l'autre se libère également. P> Ceci est le code de mon analyseur, je m'excuse pour sa forme désordonnée: p> Ceci est quand je tente de libérer: p> lorsque j'entraîne est-ce que cette hypothèse est-elle correcte? Comment puis-je surmonter cette double libération? P> P> '\ 0' code> après chaque mot "morceau". P>
"home ou pour" code> dans l'analyseur et essayez ultérieurement de le libérer, l'adresse de
"home" est
0x7FFFFFFFE840 CODE> Bien que l'adresse de
"pour" code> est
0x7fffffffe848 code>. Cela me conduit à croire que la libération de
home code> est également libérer
ou code> provoquant une erreur SIGABRT ultérieurement. P>
3 Réponses :
Vous devez seulement appeler gratuit () code> sur des pointeurs retournés par
malloc () code>,
calloc () code> ou
realloc () code>. On dirait que vous faites:
home
or
for
Ce n'est pas un analyseur, cependant. Plus un tokenizer.
#include <assert.h> #include <errno.h> #include <stddef.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> bool parser(char const *str, char ***words, size_t *num_words, size_t *error) { // ^^^ gaaaah! *) assert(words); errno = 0; size_t length = strlen(str); for (size_t i = 0; i < length; ++i) { if (!isalnum(str[i]) && !isspace(str[i])) { *error = i; // the position is most likely more meaningful than the character return false; // get outta here!! } } char const *begin; char const *end; *num_words = 0; *words = NULL; bool in_word = false; for (size_t i = 0; i <= length; ++i) { if (!in_word && isalnum(str[i])) { // word begins begin = str + i; in_word = true; } else if (in_word && !isalnum(str[i])) { // word ended end = str + i; char *word = calloc(end - begin + 1, sizeof *word); if (!word) { for (size_t i = 0; i < num_words; ++i) free((*words)[i]); free(*words); errno = ENOMEM; return false; } memcpy(word, begin, end - begin); char **tmp = realloc(*words, (*num_words + 1) * sizeof *tmp); if (!tmp) { free(word); for (size_t i = 0; i < num_words; ++i) free((*words)[i]); free(*words); errno = ENOMEM; return false; } *words = tmp; tmp[(*num_words)++] = word; in_word = false; } } return true; } int main(void) { char const *foo = "slfkja askdfj jk j aksjf lasjdflkjsdlf jask fdjl"; char **words = NULL; size_t num_words = 0; size_t error = 0; if (!parser(foo, &words, &num_words, &error)) { if (errno == ENOMEM) fputs("Not enough memory. :(\n\n", stderr); else fprintf(stderr, "Error at position %zu: \"%s\"\n\n", error, foo + error); return EXIT_FAILURE; } puts("List of words:"); for (size_t i = 0; i < num_words; ++i) { printf("\"%s\"\n", words[i]); free(words[i]); } free(words); }
C devrait être renommé brainf * ck ...
vous modifiez la valeur de str
dans le corps de la fonction (dans la ligne str = new;
(n'utilisez pas new < / code> comme identifiant, plus si vous prévoyez d'utiliser ce code comme code C ++, car
new
est un mot réservé en C ++). Comme vous n'appelez pas malloc (3) < / code> dans le corps de la fonction, il est tout à fait normal que vous rencontriez un problème de
free (3)
, car free nécessite de passer un pointeur précédemment généré avec malloc (et uniquement une fois, vous ne pouvez donc pas l'appeler deux fois avec le même pointeur). C'est la raison pour laquelle vous obtenez SIGABRT
et autres. En règle générale, n'appelez pas free (3) < / code> dans une fonction que vous n'appelez pas également malloc pour le même pointeur . Cette utilisation est sujette à des erreurs et vous rencontrerez des problèmes plus d'une fois par jour si vous insistez pour tout faire en un seul fonction.
mieux que de s'excuser pour la forme désordonnée du code, veuillez le nettoyer avant de poster Publiez un minimu (c'est-à-dire le code minimum qui montre l'erreur), complet (ce qui signifie que nous pouvons le compiler et observer le résultat que vous publiez comme un échec), vérifiable (code qui montre qu'il produit le résultat observé, et non celui attendu) et complet (cela signifie que nous n'avons rien d'autre à faire que de le compiler et de l'exécuter) du code (afin que nous puissions le tester en échec comme vous le dites, sans avoir à le corriger au préalable) De cette façon, nous pouvons faire un diagnostic de ce qui se passe dans votre code. Si nous devons corriger le code juste pour le rendre exécutable, nous pouvons corriger le problème principal que vous observez et ne pas voir l'erreur. Vous voyez? :)
new
comme identifiant dans le code C: De nombreux frameworks de tests unitaires exigent que votre code soit compilable en tant que code C ++, afin qu'il puisse être utilisé par le framework (au moins Google Test l'exige) Si vous prévoyez d'écrire des tests unitaires pour votre code, rappelez-vous que new
est un mot réservé en C ++ pour l'opérateur new
, et ainsi, votre code produira des erreurs de syntaxe si vous essayez de le compiler avec un compilateur c ++. Mieux vaut si vous ne l'utilisez pas.
Questions à la recherche d'aide de débogage («Pourquoi ce code ne fonctionne pas?») Doit inclure le comportement souhaité, un problème ou une erreur spécifique et le code le plus court nécessaire pour la reproduire dans la question elle-même. Les questions sans déclaration de problème clair ne sont pas utiles à d'autres lecteurs. Voir: Comment créer un exemple de reproductible minimal .
isspace (str [i]) == 0 && isalpha (str [i]) == 0
-isalnum ()
... -nonAlphaSpace = true;
- pourquoi ne pas simplement revenir?Je ne vois pas où vous
malloc ()
quoi que ce soit, alors pourquoi appelez-vousfree ()
?Comment attribuez-vous la chose que vous passez comme premier argument à
parser ()
en premier lieu?Merci d'avoir regardé et je m'excuse pour le format des questions en désordre, je vais essayer de m'améliorer dans les questions futures. Sur la question du retour s'il y a un mauvais caractère, je l'ai fait parce que je voulais retourner un type char ** initialement, donc un seul char * retournant aurait été problématique. Mais plus tard, quand j'ai essayé de compiler, le compilateur a averti que les variables locales n'étaient pas sages à retourner, et j'ai donc changé plus tard le type de retour en
void
. C'est très inefficace et convulté et encore une fois, je m'en excuse.J'ai passé la chaîne en lisant une ligne via
stdin
.Vous ne répondez pas à la question.
vous n'affichez ni le code où vous faites
malloc (3)
ni le code où vous faitesfree (3)
alors de quoi parle ce code? Sur quoi porte la question? Que voulez-vous dire par libération? Voulez-vous dire appelergratuitement (3)
? que voulez-vous dire par certains de mes mots ont la même adresse d'octet ???Pourquoi essayez-vous de résoudre beaucoup de problèmes dans la même fonction, pourquoi ne pas simplement essayer d'obtenir le mot suivant, puis de l'ajouter à la liste des chaînes. Je ne vois pas la nécessité de naviguer au moins trois fois la chaîne entière pour obtenir sa longueur, puis pour vérifier les caractères valides, puis ...
Veuillez ne pas utiliser
new
comme identifiant en C, car vous pouvez rencontrer des problèmes si vous essayez plus tard d'utiliser ce code en C ++.