free() sur tableau dynamiques à 4 dimensions

free() sur tableau dynamiques à 4 dimensions - C - Programmation

Marsh Posté le 26-08-2006 à 16:11:39    

Salut,
J'ai un leger problème avec du code que j'ai tapé :(
Le programme fait ce qu'il faut, mais plante à la fin, à la libération de la mémoire !
 
Je met un exemple de la création du tableau 4 dimensions et de sa libération, si quelqu'un veux bien regarder ce qui cloche, ce serait très sympa :
J'ai légerement modifié pour que vous ayez une taille si vous voulez tester. Ceci crée un tableau w[10][3][2][2] qu'on peut utiliser comme un tableau 4 dimensions classiques (ex : w[0][0][0][0]=1.0;).
 

Code :
  1. double ****w;
  2. w = (double****)malloc(10*sizeof(double));
  3. for (i=0; i<10; i++){
  4.  w[i] = (double***)malloc(3*sizeof(double));
  5.      for (j=0; j<3; j++){
  6.           w[i][j] = (double**)malloc(2*sizeof(double));
  7.           for (k=0; k<2; k++){
  8.               w[i][j][k] = (double*)malloc(2*sizeof(double));
  9.           }
  10.      }
  11. }
  12. for (i=0; i<10; i++){
  13.      for (j=0; j<3; j++){
  14.           for (k=0; k<2; k++){
  15.                     free(w[i][j][k]);
  16.           }
  17.           free(w[i][j]);
  18.      }
  19.      free(w[i]);
  20. }     
  21. free(w);


 
Il y a plusieurs tableaux de ce genre dans le code (1,2,3 ou 4 dimensions). Or il semblerait qu'il plante la dessus mais aléatoirement (des fois il plante sur un autre free()).
Si je vire la partie de libération mémoire, mon programme marche nickel, mais j'ai peur que ca pose des problèmes de pas libérer la mémoire ?
 
Merci de votre aide.

Reply

Marsh Posté le 26-08-2006 à 16:11:39   

Reply

Marsh Posté le 26-08-2006 à 18:35:57    

D'une façon générale, il est très rare qu'on dépasse "**" en dimensions car après, on arrive plus à bien visualiser.
Mais le pb vient des malloc initiaux.
 

cheetwoox a écrit :

Code :
  1. double ****w;
  2. w = (double****)malloc(10*sizeof(double));



"w" est un "double étoile étoile étoile étoile" donc à l'adresse pointée par "w" (qu'on peut nommer "w[0]" ou "*w" ), on a un "double étoile étoile étoile". Et toi, tu veux allouer 10 valeurs de ce type donc le bon malloc est

Code :
  1. double ****w
  2. w = (double ****)malloc(10*sizeof(double ***));


 
Idem pour les autres malloc. A chaque sous-niveau, tu supprimes une étoile...
 
Sinon, l'enchainement des free est correct.
 
Autre chose: Si les tailles à allouer sont toujours constantes, tu peux te passer des malloc et des free

Code :
  1. double w[10][3][2][2];

Message cité 1 fois
Message édité par Sve@r le 26-08-2006 à 18:39:21

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 26-08-2006 à 20:51:52    

Ok, genial j'avais pas fait attention à cette erreur ^^.
Pour les tailles elles ne sont malheureusement pas fixes...
Merci beaucoup je vais essayer ça !

Reply

Marsh Posté le 26-08-2006 à 21:23:37    

Sve@r a écrit :

D'une façon générale, il est très rare qu'on dépasse "**" en dimensions car après, on arrive plus à bien visualiser.
Mais le pb vient des malloc initiaux.
 
"w" est un "double étoile étoile étoile étoile" donc à l'adresse pointée par "w" (qu'on peut nommer "w[0]" ou "*w" ), on a un "double étoile étoile étoile". Et toi, tu veux allouer 10 valeurs de ce type donc le bon malloc est

Code :
  1. double ****w
  2. w = (double ****)malloc(10*sizeof(double ***));




C'est pour çà (entre autres), qu'on préfère l'écriture :  

Code :
  1. double ****w = malloc (nb_t * sizeof *w);


C'est beaucoup plus clair... ensuite :  

Code :
  1. w[i] = malloc (nb_z * sizeof *w[i]);
  2. ...
  3. w[i][j] = malloc (nb_y * sizeof *w[i][j]);
  4. ...
  5. w[i][j][k] = malloc (nb_x * sizeof *w[i][j][k]);


avec, ici, si j'ai bien compris,

nb_x = 2
nb_y = 2
nb_z = 3
nb_t = 10 ...


Message édité par Emmanuel Delahaye le 26-08-2006 à 21:28:29

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 26-08-2006 à 22:32:01    

Je connaissais pas cette écriture, ça condense plutôt bien et c'est bien lisible, je vais l'essayer (et surement l'adopter) :) Mais il faut quant même les boucles car on alloue de l'espace dans chaque case ?
 
Sinon il semble qu'il n'est pas possible d'allouer un tableau dynamique dans un sous programme si on veut l'utiliser dans un programme principal car j'ai essayé de passer ****w a un sous programme et d'allouer, mais ensuite ca ne fonctionne pas dans le programme principal si je veux l'utiliser. Idem pour la libération mémoire.
 
En fait ce serait pour faire plus propre dans le programme principal en plaçant les nombreuses lignes dans un sous programme.

Reply

Marsh Posté le 26-08-2006 à 22:49:42    

J'ai écrit ça mais il plante toujours sur la libération :
 

Code :
  1. double ****w;
  2. w = (double****)malloc(nbNrLig*sizeof(double***));
  3. for (i=0; i<nbNrLig; i++){
  4.      w[i] = (double***)malloc(nbColNr*sizeof(double**));
  5.      for (j=0; j<nbColNr; j++){
  6.           w[i][j] = (double**)malloc(2*sizeof(double*));
  7.           for (k=0; k<2; k++){
  8.               w[i][j][k] = (double*)malloc(2*sizeof(double));
  9.           }
  10.      }
  11. }
  12. for (i=0; i<nbNrLig; i++){
  13.      for (j=0; j<nbColNr; j++){
  14.           for (k=0; k<2; k++){
  15.                free(w[i][j][k]);
  16.           }
  17.           free(w[i][j]);
  18.      }
  19.      free(w[i]);
  20. }     
  21. free(w);


 
J'ai fait une erreur ?

Reply

Marsh Posté le 27-08-2006 à 01:35:47    

cheetwoox a écrit :

Je connaissais pas cette écriture, ça condense plutôt bien et c'est bien lisible, je vais l'essayer (et surement l'adopter) :) Mais il faut quant même les boucles car on alloue de l'espace dans chaque case ?


Oui, bien sûr, je n'ai mis que l'essentiel...

Citation :


Sinon il semble qu'il n'est pas possible d'allouer un tableau dynamique dans un sous programme si on veut l'utiliser dans un programme principal car j'ai essayé de passer ****w a un sous programme et d'allouer, mais ensuite ca ne fonctionne pas dans le programme principal si je veux l'utiliser. Idem pour la libération mémoire.


Bien sûr que si. Le plus simple est de retourner une adresse de type T****.
(T étant le type que utilises, int, je crois...)

Citation :


En fait ce serait pour faire plus propre dans le programme principal en plaçant les nombreuses lignes dans un sous programme.


Absolument, il est même fortement recommandé de faire comme ça. Entraine toi sur un tableau à 1 ou 2 dimensions. Commencer par 4 dimensions sans connaître certaines bases du C, c'est un peu casse-gueule...


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 27-08-2006 à 03:22:30    

cheetwoox a écrit :

J'ai écrit ça mais il plante toujours sur la libération :


Ton code est correct. Comment tu sais que ça plante ? Il se passe quoi ?  
 
Ceci fonctionne et dispose de plus de contrôles :  

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void)
  4. {
  5.    size_t const nbNrLig = 4;
  6.    size_t const nbColNr = 3;
  7.    size_t i;
  8.    double ****w = malloc(nbNrLig * sizeof * w);
  9.    if (w != NULL)
  10.    {
  11.       for (i = 0; i < nbNrLig; i++)
  12.       {
  13.          size_t j;
  14.          w[i] = malloc(nbColNr * sizeof * w[i]);
  15.          if (w[i] != NULL)
  16.          {
  17.             for (j = 0; j < nbColNr; j++)
  18.             {
  19.                size_t k;
  20.                w[i][j] = malloc(2 * sizeof * w[i][j]);
  21.                if (w[i][j] != NULL)
  22.                {
  23.                   for (k = 0; k < 2; k++)
  24.                   {
  25.                      w[i][j][k] = malloc(2 * sizeof * w[i][j][k]);
  26.                   }
  27.                }
  28.             }
  29.          }
  30.       }
  31.    }
  32.    for (i = 0; i < nbNrLig; i++)
  33.    {
  34.       size_t j;
  35.       for (j = 0; j < nbColNr; j++)
  36.       {
  37.          size_t k;
  38.          for (k = 0; k < 2; k++)
  39.          {
  40.             free(w[i][j][k]);
  41.          }
  42.          free(w[i][j]);
  43.       }
  44.       free(w[i]);
  45.    }
  46.    free(w);
  47.    return 0;
  48. }


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 27-08-2006 à 10:40:15    

C'est du code C compilé via Matlab, ça compile bien mais si j'affiche des textes au millieu des free(), je remarque que le programme s'arrete par là. Si je vire les free() tout passe nickel et fonctionne bien, pas de plantage :(
Se pourrait il que Matlab ait un peu de mal avec du code qui serait pourtant bon ?
En tout cas je vais essayer de déporter tout ça dans un sous programme pour voir.
Merci de votre aide.

Reply

Marsh Posté le 27-08-2006 à 10:48:26    

cheetwoox a écrit :

C'est du code C compilé via Matlab, ça compile bien mais si j'affiche des textes au millieu des free(), je remarque que le programme s'arrete par là. Si je vire les free() tout passe nickel et fonctionne bien, pas de plantage :(


J'ai toujours pas compris quel était le plantage.  
 
Dans tout les cas, il faut vérifier si il n'y a pas de débordement du tableau.
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 27-08-2006 à 10:48:26   

Reply

Marsh Posté le 27-08-2006 à 11:35:51    

Il plante bien sur les free().  
Mais il y en a plusieurs vu qu'il y a pas mal de tableaux.  
Or il plante parfois sur l'un, parfois sur l'autre (mais toujours des free) !
 
Que se passe t'il si je ne libère pas la mémoire et que je lance ce programme plusieurs milliers de fois (le système ne la libèrera pas tout seul ?) ?
 
J'ai essayé ça pour déporter la création et suppression de mémoire :
 

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. void creerC(int *c);
  4. void deleteC(int *c);
  5. int main()
  6. {
  7.      int *c;
  8.    
  9.      creerC(c);
  10.      c[0] = 1;
  11.      printf("%d\n",c[0]);
  12.      system("PAUSE" );
  13.      deleteC(c);
  14.      return 0;
  15. }
  16. void creerC(int *c)
  17. {
  18.     c = (int*)malloc(10*sizeof(int));
  19. }
  20. void deleteC(int *c)
  21. {
  22.     free(c);
  23. }


 
Ceci ne fonctionne pas (la fenêtre ne reste pas ouverte alors qu'elle le devrait). J'imagine que ce code est completement faux ?

Reply

Marsh Posté le 27-08-2006 à 13:25:01    

cheetwoox a écrit :

Il plante bien sur les free().  
Mais il y en a plusieurs vu qu'il y a pas mal de tableaux.  
Or il plante parfois sur l'un, parfois sur l'autre (mais toujours des free) !
 
Que se passe t'il si je ne libère pas la mémoire et que je lance ce programme plusieurs milliers de fois (le système ne la libèrera pas tout seul ?) ?


Ben au bout d'un moment, plus de mémoire. C'est pas génant pour un programme 'batch' ou d'usage court ou peu fréquent (le système récupère la mémoire à la fin de l'exécution). C'est évidemment catastrophique pour une application longue (système, service, serveur...)

Citation :


J'ai essayé ça pour déporter la création et suppression de mémoire :

Code :
  1. void creerC(int *c)
  2. {
  3.     c = (int*)malloc(10*sizeof(int));
  4. }


 
Ceci ne fonctionne pas (la fenêtre ne reste pas ouverte alors qu'elle le devrait). J'imagine que ce code est completement faux ?


Ben sûr que ça ne fonctione pas. Tu modifies la valeur d'un paramètre, ce qui ne sert à rien (et révèle souvent, comme ici, une erreur de conception de l'interface). Il faut retourner la valeur comme le fait malloc(). Et supprimme tous ces casts inutiles (et j'ai montré une autre façon de faire l'allocation, indépendante du type)...


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 27-08-2006 à 14:55:41    

Il y a une alternative à int****. C'est int*.
Bien que int**** soit correct, et même si c'est pas très lisible, corresponde exactement à ce que tu veux représenter, tu peut allouer un seul bloc de mémoire plûtot qu'une multitude.
 
Celà permet d'une part de rendre le programme plus lisible et résistant au niveau des allocations/désallocations, et d'autre part de prendre moins de place mémoire et d'être plus rapide.
 
Par exemple pour un tableau à deux dimensions:

Code :
  1. typedef int* Tableau2D;
  2. Tableau2D alloc2D(unsigned int d1, unsigned int d2)
  3. { return (Tableau2D)malloc(d1*d2*sizeof(int)); }
  4. void free2D(Tableau2D tab)
  5. { free(tab); }


 
Par contre pour acceder au membres du tableau tu doit jongler avec les coordonnées:

Code :
  1. inline int* acces2D(Tableau2D tab, unsigned int x, unsigned int y, unsigned int d1)
  2. { return tab+x+y*d1; }


 
Au final le code est plus propre, et à cause de l'architecture de la mémoire des ordinateurs celà reste plus rapide et économique. Tu peut aussi ajouter les contrôles de débordement si necessaire dans la fonction acces2D.
 
Accès à un tableau 4D:

Code :
  1. inline int* acces4D(Tableau4D tab,
  2.   unsigned int x, unsigned int y, unsigned int z, unsigned int t,
  3.   unsigned int d1, unsigned int d2, unsigned int d3)
  4. { return tab+x+(y+(z+t*d3)*d2)*d1; }


Reply

Marsh Posté le 30-08-2006 à 23:40:22    

Et ça évite (comme ça m'est arrivé l'an dernier) de voir des stagiaires débarquer dans ton bureau avec la question suivante: "comment je fais pour passer un ***p dans une fonction qui n'accepte que des **p ?"...
 
J'ai été incapable d'expliquer.[:benou] La prochaine fois, je filerai le numéro d'Emmanuel Delahaye.[:benou]


Message édité par el muchacho le 30-08-2006 à 23:42:32

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed