IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

besoin d'eclaircissement sur malloc et free


Sujet :

C

  1. #1
    Nouveau membre du Club
    Inscrit en
    Juin 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 48
    Points : 30
    Points
    30
    Par défaut besoin d'eclaircissement sur malloc et free
    Bonjour à tous

    Je pédale un peu dans la semoule avec ces 2 fonctions là ...
    Après quelques recherches pour avoir des exemples je suis tombé la dessus :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    /* illustration of dynamically allocated 2D array */
    #include <stdio.h>
    #include <stdlib.h>
     
    int main()
    {
      int i; /* general purpose variable used for loop index */
      int j; /* general purpose variable used for loop index */
     
      int **a;     /* this is the array name */
      int size_x; /* this variable will be used for the first  dimension */
      int size_y; /* this variable will be used for the second dimension */
     
      /* suppose we want an array of int: a[5][3] */
      size_x = 5;
      size_y = 3;
     
      /*  allocate storage for an array of pointers */
      a = malloc(size_x * sizeof(int *));
     
      /* for each pointer, allocate storage for an array of ints */
      for (i = 0; i < size_x; i++) {
        a[i] = malloc(size_y * sizeof(int));
      }
     
      /* just for kicks, show the addresses (note: not all sequential) */
      /* assign an arbitrary value to each element        */
      for (i = 0; i < size_x; i++) {
        for (j = 0; j < size_y; j++) {
          printf("&a[%d][%d] = %p\n", i, j, &a[i][j]); /* show the addresses */
          a[i][j] = i * size_y + j; /* just some unique number for each element */
        }
        printf ("\n");
      }
     
      /* now show the contents that were assigned */
      for (i = 0; i < size_x; i++) {
        for (j = 0; j < size_y; j++) {
          printf("a[%d][%d] = %2d\n", i, j, a[i][j]);
        }
        printf ("\n");
      }
     
      /* now for each pointer, free its array of ints */
      for (i = 0; i < size_y; i++) {
        free(a[i]);
      }
      /* now free the array of pointers */
      free(a);
     
      return 0;
    }
    Si j'ai bien compris, on crée d'abord une variable **a, en gros un pointeur sur les colonnes qui pointe sur les lignes. Puis on attribut le nombre de colonnes en faisant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = malloc(size_x * sizeof(int *));
    Et on défini le nombre de lignes en faisant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      for (i = 0; i < size_x; i++) {
        a[i] = malloc(size_y * sizeof(int));
      }
    On a donc un tableau contenant size_x colonnes, qui contiennent size_y lignes.

    Jusque là je crois que c'est bon, c'est après que ça se complique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      for (i = 0; i < size_y; i++) {
        free(a[i]);
      }
    Si je comprends bien on va libérer les lignes crée avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for (i = 0; i < size_x; i++) {
        a[i] = malloc(size_y * sizeof(int));
      }
    Mais alors pourquoi il utilise size_y pour libérer les a[i] alors que le malloc était avec size_x ?

    Je suis donc un peu embrouiller avec la libération, car selon moi il aurait fallu faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      for (i = 0; i < size_x; i++) {
        free(a[i]);
      }

  2. #2
    Membre éclairé Avatar de nsanabi
    Homme Profil pro
    Inscrit en
    Septembre 2003
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2003
    Messages : 570
    Points : 678
    Points
    678
    Par défaut
    je pense que tu as raison, c'est peut etre une erreur du clavier, sinon est ce que le programme ne represente aucune erreurs?

    (que size_x soit le nombre de lignes et size_y celui des colonnes ou l'inverse reste conventionnel)

  3. #3
    Nouveau membre du Club
    Inscrit en
    Juin 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 48
    Points : 30
    Points
    30
    Par défaut
    merci pour la réponse. J'ai fais un bout de code juste pour tester malloc et free :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <stdio.h>
    #include <stdlib.h>
     
    int main()
    {
      int i = 0, x = 5, y = 10;
      int **tableau2D = NULL;
     
      tableau2D = malloc((x) * sizeof(int*));
     
      for(i = 0 ; i < x ; i++)
      {
        tableau2D[i] = malloc((y) * sizeof(int));
      }
     
      for(i = 0 ; i < x ; i++)
      {
        free(tableau2D[i]);
      }
      free(tableau2D);
    }
    j'ai essayé avec plusieurs valeurs pour x et y, il ne fais pas d'erreur de segmentation ou autre, il doit donc être correcte.

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Mais alors pourquoi il utilise size_y pour libérer les a[i] alors que le malloc était avec size_x ?
    Pour (au choix) crasher le programme ou créer des fuites de mémoire.
    Non, sérieusement, si on alloue dynamiquement size_x zones mémoire de size_y objets de type quelconque, il faut bien sûr déallouer de la même manière.

    Dans ton code, tu devrais toutefois rajouter des tests pour vérifier si tes malloc retournent bien une valeur non NULL. Car si un des malloc renvoie NULL, que tu ne vérifies pas, puis que tu accèdes à cette adresse, le programme va inévitablement crasher. Le programme écrit tel quel présente donc un bug, susceptible de provoquer un crash, même si cela a très peu de chance d'arriver. (Ca doit arriver très rarement qu'un malloc retourne NULL sur une machine lambda)

  5. #5
    Nouveau membre du Club
    Inscrit en
    Juin 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 48
    Points : 30
    Points
    30
    Par défaut
    Ok merci pour le conseil, donc juste rajouter un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    tableau2D = malloc((x) * sizeof(int*));
     
    if(tableau2D[i] == NULL)
    {return 0;}
    Je vais essayer, parce que j'ai repris le petit code d'avant pour en faire quelque chose d'utile, mais j'ai une erreur de segmentation au moment de la libération mémoire. Le plus bizarre c'est que si je retire la fonction qui intervient sur le tableau, l'erreur de segmentation disparait et pourtant après vérification cette erreur de segmentation arrive après la fonction.

  6. #6
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Ok merci pour le conseil, donc juste rajouter un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    tableau2D = malloc((x) * sizeof(int*));
     
    if(tableau2D[i] == NULL)
    {return 0;}
    Pour le premier test : il faut tester tableau2D (pointeur de pointeur sur int) et non tableau2D[ i ], qui serait ici la valeur pointée (pointeur sur int) dans le premier élément du tableau (car dans ton code, i vaut initialement 0).

    Pour les autres tests, il faut tester aussi chaque retour de malloc dans la boucle (tableau2D[ i ]).

    Je vais essayer, parce que j'ai repris le petit code d'avant pour en faire quelque chose d'utile, mais j'ai une erreur de segmentation au moment de la libération mémoire. Le plus bizarre c'est que si je retire la fonction qui intervient sur le tableau, l'erreur de segmentation disparait et pourtant après vérification cette erreur de segmentation arrive après la fonction.
    Il faut nous montrer ton code modifié.

  7. #7
    Nouveau membre du Club
    Inscrit en
    Juin 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 48
    Points : 30
    Points
    30
    Par défaut
    alors voici le morceau de code qui me pose problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    int main()
    {
      clrscr();
     
      int nombre_de_lignes = 0, i = 0;
      int *nombre_de_caracteres_par_ligne = NULL;
      char **contenu_des_lignes = NULL;
     
      nombre_de_lignes = fonction_nombre_de_lignes("test.txt");
      printf("nombre de ligne : %i\n", nombre_de_lignes);
     
      nombre_de_caracteres_par_ligne = malloc((nombre_de_lignes) * sizeof(int));
      fonction_nombre_de_caracteres_par_ligne("test.txt", nombre_de_caracteres_par_ligne);
      for(i = 0 ; i < nombre_de_lignes ; i++)
      {
        printf("nombre de caracteres à la ligne %i : %i\n", i, nombre_de_caracteres_par_ligne[i]);
      }
     
      contenu_des_lignes = malloc((nombre_de_lignes) * sizeof(char*));
      for(i = 0 ; i < nombre_de_lignes ; i ++)
      {
        contenu_des_lignes[i] = malloc((nombre_de_caracteres_par_ligne[i]) * sizeof(char));
      }
     
      printf("lecture du fichier\n");
      lecture_du_fichier("test.txt", contenu_des_lignes);
      printf("fin de la lecture du fichier\n");
     
      afficher_chaine(&contenu_des_lignes[0]);
      printf("\n");
      afficher_chaine(&contenu_des_lignes[1]);
      printf("\n");
      afficher_chaine(&contenu_des_lignes[2]);
      printf("\n");
     
      printf("liberation de la memoire\n");
      for(i = 0 ; i < nombre_de_lignes ; i ++)
      {
        free(contenu_des_lignes[i]);
      }
      free(contenu_des_lignes);
      free(nombre_de_caracteres_par_ligne);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    int lecture_du_fichier(char nom_du_fichier[], char *contenu_des_lignes)
    {
      int i = 0;
      char caractere = '0';
     
      FILE *fichier = NULL;
      fichier = fopen(nom_du_fichier, "r");  
      test_ouverture(fichier,nom_du_fichier);
     
      do 
      {
        caractere = fgetc(fichier);
        if( caractere == '\n')
        {*(contenu_des_lignes + i) = '\0';}
        else if( caractere == EOF)
        {
          printf("fin du fichier\n");
          *(contenu_des_lignes + i) = '\0';
          printf("%i\n", i);
          return 1;
        }
        else{*(contenu_des_lignes + i) = caractere;}
        i++;
      }while(caractere != EOF && i<35);
    };
    Je pense que les noms sont assez explicite pour comprendre ce qu'il se passe dans la fonction. En fait je cherche a faire une petite fonction qui me permettrait d'une part de lire ligne par ligne un fichier et par la suite si ça marche chercher des données spécifiques, par exemple faire une liste de coordonnées ou de noms de fichiers à ouvrir tout en y mettant des commentaires.


    Une fois compilé et exécuté mon code renvoie la chose suivante à la console :

    ouverture du fichier : test.txt
    nombre de ligne : 3
    ouverture du fichier : test.txt
    nombre de caracteres à la ligne 0 : 8
    nombre de caracteres à la ligne 1 : 14
    nombre de caracteres à la ligne 2 : 16
    lecture du fichier
    ouverture du fichier : test.txt
    fin de la lecture du fichier
    bonjour
    tout le monde
    monde
    liberation de la memoire
    Erreur de segmentation
    Premier soucis c'est que le fichier test.txt contient :
    "bonjour
    tout le monde
    comment ca va ?"

    Ca se passe donc très bien pour les 2 premières lignes, mais ça cafouille à la 3eme... Mais comme vous pouvez le voir, le :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("liberation de la memoire\n");
    est exécuté, ce n'est qu'après que l'erreur de segmentation survient.

    J'ai du faire une bêtise quelque part mais je ne vois pas où ...

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    J'aurais fait quelque chose dans ce style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MODE_TEST
     
    #define BUFFER_MAXI 50
     
    int comptage_lignes(FILE * fichier)
    {
    	char buffer[BUFFER_MAXI];
    	char * s;
    	int erreur = 0;
    	int nombre_lignes;
     
    	nombre_lignes = 0;
    	while ( (s = fgets( buffer , BUFFER_MAXI , fichier)) != NULL)
    	{
    		if ( (s = strchr(buffer , '\n')) != NULL)
    			*s = 0;
    		if ( (s = strchr(buffer , '\r')) != NULL)
    			*s = 0;
    		if ( *buffer != 0 ) /* si une ligne est vide, on ne la compte pas */
    			nombre_lignes++;
    	}
    	if ( nombre_lignes == 0 )
    		printf("Le fichier est vide.\n");
     
    	if ( fseek( fichier , SEEK_SET , 0 ) != 0 )
    	{
    		printf("Echec de fseek\n");
    		erreur = 1;
    	}
     
    #ifdef MODE_TEST
    	if ( !erreur)
    		printf("Nombre lignes : %d\n\n", nombre_lignes);
    #endif
     
    	return erreur ? 0 : nombre_lignes;
    }
    void remplit_ligne (FILE * fichier , char ** contenu_des_lignes )
    {
    	char buffer[BUFFER_MAXI];
    	char * s;
     
    	*contenu_des_lignes = NULL;
     
    	do
    	{
    		s = fgets( buffer , BUFFER_MAXI , fichier);
    		if (s != NULL)
    		{
    			if ( (s = strchr(buffer , '\n')) != NULL)
    				*s = 0;
    			if ( (s = strchr(buffer , '\r')) != NULL)
    				*s = 0;
    			if ( *buffer != 0 ) /* on s'assure que la ligne n'est pas vide */
    			{
    				int longueur_chaine = strlen(buffer);
    				*contenu_des_lignes = malloc ( longueur_chaine + 1 );
    				if (*contenu_des_lignes != NULL )
    					strncpy( *contenu_des_lignes , buffer , longueur_chaine + 1);
     
    #ifdef MODE_TEST
    				printf("Adresse de la chaine courante : %p (%d caracteres, sans le '\\0' final)\n", *contenu_des_lignes , longueur_chaine );
    #endif
    			}
    		}
    	} while (s != NULL && *buffer == 0 ); /* on s'assure que la chaine contient au moins 1 caractère (à moins qu'une erreur ou une fin de fichier soit survenue) */
    }
    int main(void)
    {
    	FILE * fichier = NULL;
    	char **contenu_des_lignes = NULL;
    	int erreur = 0;
    	int nombre_lignes ;
     
    	/* ouverture fichier */
    	fichier = fopen("test.txt" , "rb");
    	if (fichier == NULL)
    	{
    		printf("Fichier inexistant\n");
    		erreur = 1;
    	}
     
    	/* comptage lignes */
    	if (!erreur)
    	{
    		nombre_lignes = comptage_lignes(fichier);
    		if (nombre_lignes == 0)
    			erreur = 1;
    	}
     
    	/* remplissage */
    	if (!erreur)
    	{
    		contenu_des_lignes = malloc ( nombre_lignes * sizeof *contenu_des_lignes );
     
    #ifdef MODE_TEST
    		printf("Allocation tableau de pointeur : %p\n\n", contenu_des_lignes );
    #endif
    		if ( contenu_des_lignes == NULL)
    		{
    			printf("Erreur allocation memoire\n");
    			erreur = 1;
    		} else
    		{
    			int ligne;
    			for ( ligne = 0 ; ligne < nombre_lignes ; ligne++)
    				remplit_ligne (fichier , contenu_des_lignes + ligne );
    		}
    	}
     
    #ifdef MODE_TEST
    		printf("\n\n");
    #endif
     
    	/* affichage */
    	if (!erreur)
    	{
    		int ligne;
    		for ( ligne = 0 ; ligne < nombre_lignes ; ligne++)
    		{
    			if ( contenu_des_lignes[ligne] != NULL )
    				printf("%s\n" , contenu_des_lignes[ligne] );
    		}
    	}
     
    	/* nettoyage memoire */
    	if (contenu_des_lignes != NULL)
    	{
    		int ligne;
    		for ( ligne = 0 ; ligne < nombre_lignes ; ligne++)
    			free ( contenu_des_lignes[ligne] );
    		free ( contenu_des_lignes );
    		contenu_des_lignes = NULL;
    	}
     
    	if (fichier != NULL)
    	{
    		fclose( fichier );
    		fichier = NULL ;
    	}
     
    	getchar();
     
    	return 0;
    }

  9. #9
    Nouveau membre du Club
    Inscrit en
    Juin 2009
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 48
    Points : 30
    Points
    30
    Par défaut
    merci pour ce code, je vais regarder en détail ce que tu as fais pour bien comprendre la chose.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Besoin d'eclaircissements sur Qlikview
    Par diabbs dans le forum QlikView
    Réponses: 0
    Dernier message: 08/04/2013, 00h35
  2. Besoin d'eclaircissement sur la MMU
    Par Odulo dans le forum Linux
    Réponses: 1
    Dernier message: 22/11/2010, 08h52
  3. besoin de comprehension sur free() et pointeur
    Par leprofmelo dans le forum C
    Réponses: 44
    Dernier message: 22/11/2007, 10h22
  4. Besoin d'eclaircissement sur la persistence
    Par willoi dans le forum Hibernate
    Réponses: 2
    Dernier message: 26/06/2007, 18h01
  5. besoins d'eclaircissements sur les dossiers cron.*
    Par rhaamo dans le forum Administration système
    Réponses: 5
    Dernier message: 23/02/2007, 11h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo