0
votes

J'ai tenté d'analyser une chaîne en mots différents, j'ai tenté de les libérer plus tard, mais 2 des chaînes ont les mêmes adresses d'octet

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 '\ 0' après chaque mot "morceau".

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.

Ceci est le code de mon analyseur, je m'excuse pour sa forme désordonnée: xxx

Ceci est quand je tente de libérer: xxx

lorsque j'entraîne "home ou pour" dans l'analyseur et essayez ultérieurement de le libérer, l'adresse de "home" est 0x7FFFFFFFE840 Bien que l'adresse de "pour" est 0x7fffffffe848 . Cela me conduit à croire que la libération de home est également libérer ou provoquant une erreur SIGABRT ultérieurement.

est-ce que cette hypothèse est-elle correcte? Comment puis-je surmonter cette double libération?


10 commentaires

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-vous free () ?


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 faites free (3) alors de quoi parle ce code? Sur quoi porte la question? Que voulez-vous dire par libération? Voulez-vous dire appeler gratuitement (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 ++.


3 Réponses :


1
votes

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


0 commentaires

1
votes

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 ...


*) Programmeur trois étoiles


0 commentaires

0
votes
  1. 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.

  2. 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? :)

Remarque sur l'utilisation de 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.


0 commentaires