10 votes

Quand dois-je utiliser free() en C ?

Le code fonctionne comme il est censé le faire, bien qu'il ne libère jamais la mémoire allouée par la fonction malloc() .

J'ai essayé de libérer de la mémoire partout où je le pouvais, mais peu importe où je le fais, cela casse le programme. Plus précisément, j'obtiens un "double free or corruption error". Il s'agit plutôt d'une question sur ce que free() y malloc() font-ils réellement ? Tous les problèmes liés à la gratuité se situent dans l'ensemble :

int main(int argc,  char *argv[]){
if(argc!=2){
    exit(1);
}

printf("CSA WC version 1.0\n\n");

int length = strlen(argv[argc-1]);
char file_to_open[length];
strcpy(file_to_open, argv[argc-1]);

//printf("filename:%s\n",file_to_open);

//create counters for output
int count_number_of_lines = 0;
int count_number_of_words = 0;
int count_number_of_characters = 0;

//create int size of default array size
int current_array_size = pre_read(file_to_open);
//printf("number of lines: %i\n",current_array_size);

//create string array of default size
char *strings_array[current_array_size];

//create a pointer to catch incoming strings
char *incoming_string=NULL;

int done=0;
while(done==0){
    incoming_string=get_line_from_file(file_to_open, count_number_of_lines);
    if(incoming_string!=NULL){
        incoming_string=csestrcpy2(incoming_string);
        //printf("incoming line: %s\n",incoming_string);
        strings_array[count_number_of_lines]=(char*)malloc(strlen(incoming_string+1));
        strings_array[count_number_of_lines]=csestrcpy2(incoming_string);
        //printf("added to array:%s\n",strings_array[count_number_of_lines]);
        count_number_of_lines++;
        count_number_of_characters=(count_number_of_characters+(strlen(incoming_string)-1));
    }
    else{
        done=1;
    }

}
//all data is stored in a properly sized array

//count all words in array
int count=0;
int word_count=0;
char *readline;

while(count<current_array_size){
    readline = csestrcpy2(strings_array[count]);
    printf("line being checked: %s", readline);

    int i=0;
    int j=1;

    while( j< strlen(readline)+1 ){
        if(strcmp(readline,"\n")!=0){
            if( (readline[i] == ' ') && (readline[j] != ' ') ){
                word_count++;
            }
            if( (readline[i] != ' ') && (readline[j] == '\n') ){
                word_count++;
            }
        }
        i++;
        j++;
    }
    count++;
}
printf("current word count: %i", word_count);
return 0;
}

char* csestrcpy2(char* src){

int i = 0;
char *dest;
char t;
dest = (char*) malloc(MAX_LINE);

while( src[i] != '\0'){

    dest[i] = src[i];
    i++;

}

dest[i] = '\0';
//printf("length:%i\n",i);
free(dest);

return dest;
}

1 votes

Il n'y a aucune raison de copier file_to_open de argv vous pouvez juste utiliser argv .

0 votes

Curieux de incoming_string=csestrcpy2(incoming_string); S'agit-il simplement d'une fonction de copie de chaîne de caractères ?

2 votes

Aussi, malloc(strlen(str+1)); est presque certainement erronée. Vous vouliez probablement dire malloc(strlen(str)+1); . (Et beaucoup de gens, dont moi, recommandent d'omettre la distribution - void * les pointeurs seront implicitement convertis, et cela peut causer des problèmes potentiels si vous les convertissez explicitement au mauvais type).

19voto

Florian Points 462

En général, vous ne devez libérer que la mémoire qui vous a été réservée dynamiquement. Cela signifie que si vous avez une déclaration comme celle-ci :

int *my_int_pointer;
my_int_pointer = malloc(sizeof(int));

que vous devez libérer la mémoire qui a été allouée (réservée) par malloc. Si vous ne savez pas où la libérer, il suffit de la libérer à la fin du programme, en utilisant free ;

free(my_int_pointer);

Dans votre fichier, il semble qu'il y aura de la mémoire allouée à chaque fois qu'il y aura une nouvelle ligne dans le fichier que vous lisez (dans l'option while(done==0) ). Ainsi, chaque fois que la if dans cette boucle, vous devez libérer la mémoire qui a été utilisée par la variable.

De plus, vous devez libérer la mémoire qui a été allouée pour la variable readline. Mais comme cela a été souligné auparavant, il se peut que vous ayez une fuite de mémoire à cet endroit.

J'espère que cela vous aidera.

edit : Okay - Je me posais déjà la question sur le csestrcpy fonction. Voyons un peu cette fonction :

char* csestrcpy2(char* src){
    int i = 0;
    char *dest;
    char t;
    dest = (char*) malloc(MAX_LINE); /*<<- This allocates memory that has to be freed*/
    while( src[i] != '\0'){
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
    //printf("length:%i\n",i);
    free(dest);                  /* This frees the memory, but you return a pointer */
    return dest;                 /* to this memory. this is invalid.                */
}

Ce que vous pouvez cependant libérer, c'est le pointeur src dans cette fonction. Mais n'oubliez pas : le pointeur ne peut pas contenir d'informations après la libération de la mémoire sous-jacente ! Il pointe simplement vers un endroit de la mémoire où il ne doit plus écrire ou lire.

De plus, la fonction copie la chaîne de caractères tant qu'il n'y a pas de ' \0 '. Que se passe-t-il s'il n'y a pas de terminateur ? La fonction continue à copier à partir de certaines adresses mémoire où elle ne devrait pas le faire !

vous ne devriez pas utiliser cette fonction ;)

0 votes

J'ai essayé de libérer la mémoire à l'endroit indiqué et j'ai obtenu le message suivant : free() : invalid pointer : 0xb76f5000 peut-être que ce n'est pas corrigeable

0 votes

Vous avez également raison au sujet de la lecture... Je dois lire un fichier puis stocker chaque ligne lue en tant que chaîne à terminaison nulle de taille appropriée dans un tableau de chaînes de caractères... cela fonctionne très bien... Puis-je libérer la mémoire allouée à ce tableau si je veux lire le tableau plus tard ? Si je la libère, puis-je encore lire le tableau ? Combien de mémoire puis-je malloc() avant que mon programme ne s'arrête ?

0 votes

Ce n'est pas la syntaxe pour free .

7voto

Keith Thompson Points 85120

Il faut lancer un appel à free() pour chaque appel réussi à malloc() .

Ce n'est pas nécessairement signifie que vous devez avoir un nombre égal de malloc() y free() dans votre code ; cela signifie que pour chaque malloc() qui est exécuté lorsque votre programme s'exécute, vous devez appeler free() en lui transmettant la valeur du pointeur que vous avez obtenu à partir de malloc() . malloc() alloue de la mémoire ; free() indique au système que vous avez fini d'utiliser la mémoire allouée.

(Vous pouvez presque certainement vous en sortir sans free()ing La mémoire allouée à la fin de votre programme sera récupérée par le système d'exploitation, mais pour des raisons de style et de bonne pratique, vous devriez quand même faire correspondre la mémoire allouée à la mémoire de votre programme. malloc() s avec free() s.)

J'ignore calloc() y realloc() appels.

0 votes

Pourriez-vous décrire le(s) scénario(s) où l'utilisation de free() est une nécessité absolue ? Puisque c'est le système d'exploitation qui s'en charge, pourquoi quelqu'un devrait-il l'utiliser (à part pour avoir une "bonne pratique de programmation") ?

3 votes

@VikasGoel : Considérons un programme qui boucle indéfiniment, allouant de la mémoire à chaque itération. S'il ne libère pas la mémoire qui lui est allouée, il sera rapidement à court de mémoire.

3voto

Dayal rai Points 4370

L'allocation dynamique de mémoire (malloc) alloue un bloc de mémoire de la taille demandée et renvoie un pointeur au début de ce bloc. Comme nous avons pris ce bloc en mémoire, il est bon de le renvoyer en mémoire une fois la tâche terminée.

Pour répondre à votre question, pour être toujours en sécurité, vous pouvez appeler la fonction libre avant de faire le retour.

main{
    int *i;
    ..
    ..
    i=(int *)malloc(sizeof(int));
    ...//so something with i
    ..
    free(i);
    return 0;
}

0voto

Ed S. Points 70246

En règle générale, pour chaque malloc il devrait y avoir un correspondant free . Vous ne pouvez cependant pas free quelque chose deux fois (comme vous l'avez déjà remarqué). Je ne vois pas d'appel à free dans votre code, il est donc impossible de dire où se situe votre problème, mais j'ai tout de suite remarqué que vous malloc de la mémoire et l'affecter à readline à l'intérieur d'une boucle, et pourtant vous n'appelez pas free en readline à la fin de la boucle, donc vous avez une fuite de mémoire à cet endroit.

0 votes

Si je le libère à la fin de la boucle, le programme meurt... si je le libère après la boucle, le programme meurt... si je le libère à la fin du programme, le programme meurt.... cela semble aller comme ça pour n'importe quelle combinaison de libérations à n'importe quel moment du programme...

0 votes

@Koffee : Ce n'est certainement pas le cas. Je voulais dire à la fin de chaque itération . Le nombre d'itérations est inconnu, vous devez donc faire le ménage après vous. Que faire si vous lisez un fichier énorme ? Ne concevez pas votre code pour qu'il ne fonctionne que dans les conditions les plus triviales, et vous devriez prendre l'habitude d'écrire du code correct de toute façon.

0voto

Chris Points 19350

Pensez à malloc y free comme "début" et "fin". À chaque fois que vous appelez malloc faites ce que vous devez faire et une fois que vous avez terminé, appelez toujours free . Assurez-vous de ne le libérer qu'une seule fois, le double-free est une erreur d'exécution.

Si vous perdez d'une manière ou d'une autre la valeur renvoyée par malloc (oui, c'est ce qui se passe avec votre code), alors vous avez une fuite de mémoire (et les portes de l'enfer s'ouvrent, yada yada).

Pour réitérer : libérez tout ce que malloc retourne (sauf null).

0 votes

Comment puis-je supprimer la fuite de mémoire ? ou au moins trouver où elle se trouvait ?

0 votes

Vous ne pouvez pas "tuer" une fuite de mémoire, elle se produit lorsque votre programme se termine sans libérer la mémoire qu'il a allouée. La plupart des systèmes d'exploitation assurent eux-mêmes le suivi de la mémoire allouée et libérée, mais il n'y a aucune garantie. Vous devrez redémarrer votre système d'exploitation pour récupérer la mémoire. Vous compilez votre programme en activant le support de débogage (-g dans gcc), puis vous utilisez un débogueur tel que gdb ou valgrind. valgrind possède même un outil appelé memcheck qui affiche la liste des mémoires qui ont été allouées (et où).

0 votes

Merci beaucoup, j'ai aussi trouvé un moyen de réécrire le code qui ne nécessite qu'un seul malloc()... J'apprécie toute votre aide !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X