Pourquoi est-ce que j'obtiens une double erreur gratuite avec realloc() ?

J'ai essayé d'écrire une fonction de remplacement de chaîne en C, qui fonctionne sur un char *, qui a été alloué à l'aide de malloc(). C'est un peu différent en ce sens qu'il trouvera et remplacera des chaînes, plutôt que des caractères dans la chaîne de départ.

C'est trivial à faire si les chaînes de recherche et de remplacement ont la même longueur (ou si la chaîne de remplacement est plus courte que la chaîne de recherche), car j'ai suffisamment d'espace alloué. Si j'essaie d'utiliser realloc(), j'obtiens une erreur qui me dit que je fais un double free - dont je ne vois pas comment je suis, puisque je n'utilise que 3.

Peut-être qu'un petit code vous aidera :

void strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while (find = strstr(find, search)) {

        if (delta > 0) {
            realloc(input, strlen(input) + delta);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) - (find - input));
        memmove(find, replace, replaceLen);
    }
}

Le programme fonctionne, jusqu'à ce que j'essaie de realloc() dans une instance où la chaîne remplacée sera plus longue que la chaîne initiale. (Cela fonctionne toujours, cela crache juste des erreurs ainsi que le résultat).

Si cela peut vous aider, le code d'appel ressemble à :

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void strrep(char *input, char *search, char *replace);

int main(void) {
    char *input = malloc(81);

    while ((fgets(input, 81, stdin)) != NULL) {
        strrep(input, 'Noel', 'Christmas');
    }
}
请先 登录 后评论

5 réponses

John Downey

Juste un coup dans le noir parce que je ne l'ai pas encore essayé, mais lorsque vous réaffectez, il renvoie le pointeur un peu comme malloc. Étant donné que realloc peut déplacer le pointeur si nécessaire, vous travaillez probablement sur un pointeur non valide si vous ne procédez pas comme suit :

input = realloc(input, strlen(input) + delta);
请先 登录 后评论
Lasse Vågsæther Karlsen

Remarque, essayez de modifier votre code pour vous débarrasser des codes d'échappement html.

Eh bien, même si cela fait un moment que je n'ai pas utilisé C/C , realloc qui grandit ne réutilise la valeur du pointeur de mémoire que s'il y a de la place en mémoire après votre bloc d'origine.

Par exemple, considérez ceci :

(xxxxxxxxxx..........)

Si votre pointeur pointe vers le premier x, et . signifie un emplacement mémoire libre et que vous augmentez la taille de la mémoire pointée par votre variable de 5 octets, cela réussira. Il s'agit bien sûr d'un exemple simplifié car les blocs sont arrondis à une certaine taille pour l'alignement, mais de toute façon.

Cependant, si vous essayez par la suite de l'augmenter de 10 octets supplémentaires et qu'il n'y en a que 5 disponibles, il devra déplacer le bloc en mémoire et mettre à jour votre pointeur.

Cependant, dans votre exemple, vous transmettez à la fonction un pointeur vers le caractère, pas un pointeur vers votre variable, et donc bien que la fonction strrep puisse en interne ajuster la variable utilisée, il s'agit d'une variable locale vers le strrep et votre code d'appel conservera la valeur de la variable de pointeur d'origine.

Cette valeur de pointeur, cependant, a été libérée.

Dans votre cas, l'entrée est le coupable.

Cependant, je ferais une autre suggestion. Dans votre cas, il semble que la variable input soit effectivement une entrée, et si c'est le cas, elle ne devrait pas être modifiée du tout.

J'essaierais donc de trouver une autre façon de faire ce que vous voulez faire, sans changer l'entrée, car des effets secondaires comme celui-ci peuvent être difficiles à détecter.

请先 登录 后评论
Vincent Robert

En règle générale, vous ne devriez jamais effectuer une libération ou une réallocation sur un tampon fourni par l'utilisateur. Vous ne savez pas où l'utilisateur a alloué l'espace (dans votre module, dans une autre DLL), vous ne pouvez donc utiliser aucune des fonctions d'allocation sur un tampon utilisateur.

À condition que vous ne puissiez plus effectuer de réallocation au sein de votre fonction, vous devriez modifier un peu son comportement, comme faire un seul remplacement, afin que l'utilisateur puisse calculer la longueur maximale de la chaîne résultante et vous fournir un tampon suffisamment long pour que ce remplacement se produise.

Ensuite, vous pouvez créer une autre fonction pour effectuer les remplacements multiples, mais vous devrez allouer tout l'espace pour la chaîne résultante et copier la chaîne d'entrée de l'utilisateur. Ensuite, vous devez fournir un moyen de supprimer la chaîne que vous avez allouée.

Entraînant :

void  strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void  strrepmfree(char *input);
请先 登录 后评论
Piotr Tyburski

Mes conseils rapides.

Au lieu de :
void strrep(char *input, char *search, char *replace)
essayez :
void strrep(char *&input, char *search, char *replace)

et que dans le corps :
input = realloc(input, strlen(input) + delta);

Lire généralement sur la transmission d'arguments de fonction en tant que valeurs/référence et description de realloc() :).

请先 登录 后评论
Mark

Cela semble fonctionner ;

char *strrep(char *string, const char *search, const char *replace) {
    char *p = strstr(string, search);

    if (p) {
        int occurrence = p - string;
        int stringlength = strlen(string);
        int searchlength = strlen(search);
        int replacelength = strlen(replace);

        if (replacelength > searchlength) {
            string = (char *) realloc(string, strlen(string) 
                + replacelength - searchlength + 1);
        }

        if (replacelength != searchlength) {
            memmove(string + occurrence + replacelength, 
                        string + occurrence + searchlength, 
                        stringlength - occurrence - searchlength + 1);
        }

        strncpy(string + occurrence, replace, replacelength);
    }

    return string;
}

Soupir, y a-t-il un moyen de poster du code sans que ce soit nul ?

请先 登录 后评论