Forum |  HardWare.fr | News | Articles | PC | Prix | S'identifier | S'inscrire | Shop Recherche
2716 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Problème avec allocation dynamique de tableau (C)

 



 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Problème avec allocation dynamique de tableau (C)

n°1870319
MKflo84
Posté le 06-04-2009 à 22:34:15  profilanswer
 

Bonjour à tous,
 
Maintes excuses, j'ai cherché des réponses à ce sujet sur le forum et j'ai trouvé un élément de réponse, seulement je ne comprends pas pourquoi mon code ne fonctionne pas.
 
Je m'explique simplement :
 
Je souhaite créer à terme des tableaux de taille variable à l'exécution d'où mon intention d'utiliser l'allocation dynamique.
 
J'ai commencé par le code suivant :
 

Code :
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. void main(){
  4. int i=0;
  5. int n=2;
  6. int p=2;
  7. double ** tab;
  8. tab=(double **)malloc(n*sizeof(double *));
  9. for( i=0;i<n;i++);
  10. {
  11. tab[i]=(double *) malloc(p*sizeof(double));
  12. }
  13. tab[0][0]=1;
  14. tab[0][1]=0;
  15. tab[1][0]=0;
  16. tab[1][1]=1;
  17. printf("%1.0f %1.0f\n",tab[0][0],tab[0][1]);
  18. printf("%1.0f %1.0f\n",tab[1][0],tab[1][1]);
  19. getchar();
  20. }


 
J'obtiens à l'exécution un exception d'accès en écriture (sous VS 2008 express) dès la première ligne d'affectation tab[0][0]=1;.
 
 
J'ai trouvé un topic similaire où le code suivant fonctionne :

Code :
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. void main(){
  4. int ** tab;
  5. int i;
  6. int j;
  7. int k=2,n=2;
  8. tab = (int ** ) malloc (k * sizeof (int*));
  9. for (i=0;i<k;i++)
  10. {
  11. tab[i]=(int *)malloc(n * sizeof(int));
  12. }
  13. for (i = 0; i < k; i = i + 1)
  14. {
  15.      for (j = 0; j < n; j = j + 1)
  16. {
  17.  tab[i][j] = i+j;
  18. }
  19. }
  20. printf("%i %i\n",tab[0][0],tab[0][1]);
  21. printf("%i %i\n",tab[1][1],tab[1][1]);
  22. getchar();
  23. }


 
Je ne comprends pas pourquoi ce dernier fonctionne tandis que le mien plante lamentablement... un petit peu d'aide serait très appréciée !
Merci à tous,
 
Flo

Message cité 1 fois
Message édité par MKflo84 le 06-04-2009 à 22:39:41
mood
Publicité
Posté le 06-04-2009 à 22:34:15  profilanswer
 

n°1870369
billgatesa​nonym
Posté le 07-04-2009 à 01:07:27  profilanswer
 

Remarque préliminaire : il manque #include <malloc.h> mais peut-être que cet include est fait automatiquement.
 
tab[0][0]=1; ne convient pas, car c'est équivalent à "la cellule mémoire qui se trouve à l'adresse de tab + 0 fois le nombre de colonnes + 0 = 1." Il y a deux problèmes : a) le nombre de colonnes n'étant pas spécifié, je ne sais pas ce que le compilateur va prendre, peut-être zéro ; b) l'adressage concerne le pointeur au lieu du pointeur de pointeur.
 
Le plus simple est d'utiliser un tableau à une seule dimension, avec un simple malloc(n*p*sizeof(int)) ou bien d'utiliser des pointeurs sur des pointeurs plutôt que la notation [][] qui adresse en fait un espace à une seule dimension.

n°1870389
Joel F
Real men use unique_ptr
Posté le 07-04-2009 à 08:39:40  profilanswer
 

Oui mais non. Pour la Neme fois, voila la façon correct d'allouer un tableau 2D contigue et supportant [][] et qui respecte le cache.

 
Code :
  1. // Gestion  mémoire
  2. float** alloc2D_float( size_t h, size_t w )
  3. {
  4.   float **m;
  5.   m    = (float**)malloc( h*sizeof(float*) );
  6.   m[0] = (float*)malloc( h*w*sizeof(float) );
  7.   for(size_t i=1;i<h;i++) m[i]=m[i-1]+w;
  8.   return m;
  9. }
  10. void release2D_float( float** ptr )
  11. {
  12.   if(ptr) free(ptr[0]);
  13.   if(ptr) free(ptr);
  14. }
  15. int main()
  16. {
  17.   float** tab;
  18.   tab = alloc2D_float( 5,9);  // 5 lignes x 9 coloness
  19.   for(int i=0;i<5;++i)
  20.     for(int j=0;j<9;++j)
  21.       tab[i][j] = 1.f/(1+i+j);
  22.   release2D_float(tab);
  23. }
 

A dupliquer/generaliser pour les autres types.

 

Un tableau 2D dont les lignes sont des zones mémoires disjointes est la pire des choses à faire.

Message cité 1 fois
Message édité par Joel F le 07-04-2009 à 08:41:10
n°1870396
Emmanuel D​elahaye
C is a sharp tool
Posté le 07-04-2009 à 09:18:30  profilanswer
 

MKflo84 a écrit :

Maintes excuses, j'ai cherché des réponses à ce sujet sur le forum et j'ai trouvé un élément de réponse, seulement je ne comprends pas pourquoi mon code ne fonctionne pas.

 

Je souhaite créer à terme des tableaux de taille variable à l'exécution d'où mon intention d'utiliser l'allocation dynamique.

 

J'ai commencé par le code suivant :


Tu peux déjà corriger ça :

 

-------------- Build: Debug in hello ---------------

 

Compiling: main.c
Linking console executable: bin\Debug\hello.exe
C:\dev\hello\main.c:4: warning: function declaration isn't a prototype
C:\dev\hello\main.c:4: warning: return type of 'main' is not `int'
Output size is 18.72 KB
Process terminated with status 0 (0 minutes, 1 seconds)
0 errors, 2 warnings


Ensuite, il y a un ';' après un for, ce qui fait que ce qui est après n'est effectué qu'une seule fois...

Code :
  1. for (i = 0; i < n; i++);
  2.    {
  3.       tab[i] = (double *) malloc (p * sizeof (double));
  4.    }


est équivalent à

Code :
  1. for (i = 0; i < n; i++)
  2.    {
  3.    }
  4.    {
  5.       tab[i] = (double *) malloc (p * sizeof (double));
  6.    }


Ce qui n'est évidemment pas ce que tu attends...

 

Le cast est inutile. Ne pas oublier de libérer ce qui a été alloué.

 

Ceci fonctionne :

Code :
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. int main (void)
  4. {
  5.    int i = 0;
  6.    int n = 2;
  7.    int p = 2;
  8.    double **tab = malloc (n * sizeof *tab);
  9.    for (i = 0; i < n; i++)
  10.    {
  11.       tab[i] = malloc (p * sizeof *tab[i]);
  12.    }
  13.    tab[0][0] = 1;
  14.    tab[0][1] = 0;
  15.    tab[1][0] = 0;
  16.    tab[1][1] = 1;
  17.    printf ("%1.0f %1.0f\n", tab[0][0], tab[0][1]);
  18.    printf ("%1.0f %1.0f\n", tab[1][0], tab[1][1]);
  19.    for (i = 0; i < n; i++)
  20.    {
  21.       free (tab[i]);
  22.    }
  23.    free (tab);
  24.    return 0;
  25. }



1 0
0 1

 

Process returned 0 (0x0)   execution time : 0.574 s
Press any key to continue.


Il manque des contrôles pour vérifier si l'allocation a réussi.

 

Ceci peut aider :

 

http://mapage.noos.fr/emdel/notes.htm#tabdyn_2d


Message édité par Emmanuel Delahaye le 07-04-2009 à 09:28:14

---------------
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/
n°1870402
Emmanuel D​elahaye
C is a sharp tool
Posté le 07-04-2009 à 09:43:57  profilanswer
 

Joel F a écrit :

Oui mais non. Pour la Neme fois, voila la façon correct d'allouer un tableau 2D contigue et supportant [][] et qui respecte le cache.
 

Code :
  1. // Gestion  mémoire
  2. float** alloc2D_float( size_t h, size_t w )
  3. {
  4.   float **m;
  5.   m    = (float**)malloc( h*sizeof(float*) );
  6.   m[0] = (float*)malloc( h*w*sizeof(float) );
  7.   for(size_t i=1;i<h;i++) m[i]=m[i-1]+w;
  8.   return m;
  9. }
  10. void release2D_float( float** ptr )
  11. {
  12.   if(ptr) free(ptr[0]);
  13.   if(ptr) free(ptr);
  14. }
  15. int main()
  16. {
  17.   float** tab;
  18.   tab = alloc2D_float( 5,9);  // 5 lignes x 9 coloness
  19.   for(int i=0;i<5;++i)
  20.     for(int j=0;j<9;++j)
  21.       tab[i][j] = 1.f/(1+i+j);
  22.   release2D_float(tab);
  23. }


 
A dupliquer/generaliser pour les autres types.
 
Un tableau 2D dont les lignes sont des zones mémoires disjointes est la pire des choses à faire.


Ca ne change pas grand chose, à part une allocation un peu plus longue...
 
Ton code, une fois rendu compilable et testable, a l'air de fonctionner.

Code :
  1. /* Gestion  mémoire */
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. float **alloc2D_float (size_t h, size_t w)
  5. {
  6.    float **m = malloc (h * sizeof (float *));
  7.    m[0] = malloc (h * w * sizeof (float));
  8.    {
  9.       size_t i;
  10.       for (i = 1; i < h; i++)
  11.          m[i] = m[i - 1] + w;
  12.    }
  13.    return m;
  14. }
  15. void release2D_float (float **m)
  16. {
  17.    if (m != NULL)
  18.    {
  19.       free (m[0]);
  20.    }
  21.    free (m);
  22. }
  23. void display2D_float (float **m, size_t h, size_t w)
  24. {
  25.    if (m != NULL)
  26.    {
  27.       size_t i;
  28.       for (i = 0; i < h; ++i)
  29.       {
  30.          size_t j;
  31.          for (j = 0; j < w; ++j)
  32.          {
  33.             printf ("%8.2f", m[i][j]);
  34.          }
  35.          printf ("\n" );
  36.       }
  37.    }
  38. }
  39. int main (void)
  40. {
  41.    float **tab;
  42. /* 5 lignes x 9 coloness */
  43.    tab = alloc2D_float (5, 9);
  44.    {
  45.       int i;
  46.       for (i = 0; i < 5; ++i)
  47.       {
  48.          int j;
  49.          for (j = 0; j < 9; ++j)
  50.          {
  51.             tab[i][j] = 1.f / (1 + i + j);
  52.          }
  53.       }
  54.    }
  55.    display2D_float (tab, 5, 9);
  56.    release2D_float (tab);
  57.    return 0;
  58. }



    1.00    0.50    0.33    0.25    0.20    0.17    0.14    0.13    0.11
    0.50    0.33    0.25    0.20    0.17    0.14    0.13    0.11    0.10
    0.33    0.25    0.20    0.17    0.14    0.13    0.11    0.10    0.09
    0.25    0.20    0.17    0.14    0.13    0.11    0.10    0.09    0.08
    0.20    0.17    0.14    0.13    0.11    0.10    0.09    0.08    0.08
 
Process returned 0 (0x0)   execution time : 0.018 s
Press any key to continue.



---------------
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/
n°1870438
Joel F
Real men use unique_ptr
Posté le 07-04-2009 à 10:29:42  profilanswer
 

Emmanuel Delahaye a écrit :


Ca ne change pas grand chose, à part une allocation un peu plus longue...


Bah, en terme de localité du cache et donc de perfs au final, ca change beaucoup ;)
 

Emmanuel Delahaye a écrit :


Ton code, une fois rendu compilable et testable, a l'air de fonctionner.


Ouais, j'ai recopié ça d'un source C++ un peut trop rapidement ;)

n°1870491
Emmanuel D​elahaye
C is a sharp tool
Posté le 07-04-2009 à 11:52:38  profilanswer
 

Joel F a écrit :


Bah, en terme de localité du cache et donc de perfs au final, ca change beaucoup ;)


Tu veux dire qu'on fait un tir groupé... OK.


---------------
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/
n°1870532
MKflo84
Posté le 07-04-2009 à 13:17:38  profilanswer
 

Merci à tous pour vos réponses.
 
J'ai fini par trouver hier soir tard, que tout venait de ce fameux ";" après for, qui rendait inopérante ma boucle et qui n'affectait que la dernière collonne de ma matrice. Je suis désolé d'avoir spamé le forum avec une boulette aussi grosse... mais celà a l'avantage de nous ammener à quelque chose de plus intéressant pour le profane que je suis :
 
La remarque de Joel F m'interpelle. Je comprend que la solution qu'il propose a l'avantage d'affecter des espaces contigus de mémoire pour les données (une seul malloc de taille k*n, vers lequel vont pointer les éléments du premier malloc) au lieu d'affecter autant d'espaces, potentiellement disjoints, qu'il y a de lignes pour ma "solution". Pourrais-t-on juste m'expliquer "simplement" (sans vouloir offenser personne) et un peu plus en détail ce que celà change en terme de perfs, pourquoi et si oui, me donner un ordre d'idée du rapport ? (1 ordre de grandeur ou plus ?)
 
Pour répondre à billgatesanonym, comme tab a été affecté d'après un malloc, la taille de la première dimension est connue (vu dans "la ref. du langage C" par C. Delanoy, p337 "retrouver artificiellement le formalisme du tableau" ).
 
Merci d'avance,

Message cité 1 fois
Message édité par MKflo84 le 07-04-2009 à 13:23:21
n°1870533
Emmanuel D​elahaye
C is a sharp tool
Posté le 07-04-2009 à 13:21:56  profilanswer
 

Joel F a écrit :


Ouais, j'ai recopié ça d'un source C++ un peut trop rapidement ;)


En C++, on utilise new et delete...


---------------
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/
n°1870535
Joel F
Real men use unique_ptr
Posté le 07-04-2009 à 13:31:32  profilanswer
 

Emmanuel Delahaye a écrit :


En C++, on utilise new et delete...


 
Pas pour des types POD.
En outre, ce n'es pas malloc/free qui est à proscirire, c'est :
- le melange malloc/Delete, new/free
- malloc/free sur des types objets.

mood
Publicité
Posté le 07-04-2009 à 13:31:32  profilanswer
 

n°1870537
Joel F
Real men use unique_ptr
Posté le 07-04-2009 à 13:33:53  profilanswer
 

MKflo84 a écrit :


La remarque de Joel F m'interpelle. Je comprend que la solution qu'il propose a l'avantage d'affecter des espaces contigus de mémoire pour les données (une seul malloc de taille k*n, vers lequel vont pointer les éléments du premier malloc) au lieu d'affecter autant d'espaces, potentiellement disjoints, qu'il y a de lignes pour ma "solution". Pourrais-t-on juste m'expliquer "simplement" (sans vouloir offenser personne) et un peu plus en détail ce que celà change en terme de perfs, pourquoi et si oui, me donner un ordre d'idée du rapport ? (1 ordre de grandeur ou plus ?)


 
Quand tu faix N malloc, les adresses sont potentiellement sur des pages mémoire ou du moins des zone smémoire discontinues.
Lorsque tu acces à tab[i][j], le processeur va tenter de charger tab[i][j] et ses k voisins contigus ou k est la taille d'une ligne du cache.
Avec des lignes discontinues, tu va forcement avoir des cache misses en fin de lignes car il ne pas remplir à fond sa ligne de cache.
Et en general, les cache misses = plein de cycles dans la tete car accéder au cache est 10x plus rapide que de charger depuis la memoire principale.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Problème avec allocation dynamique de tableau (C)

 

Sujets relatifs
Problème session[PHP} Probleme boucle
Problème présentation htmlProblème d'occurence variable [RESOLU]
un probléme de Scanf () ????Problème avec appendChild sous IE
Probléme avec les matricestri de plusieurs tableau
problème trigger SQL SERVER 2005 
Plus de sujets relatifs à : Problème avec allocation dynamique de tableau (C)


Copyright © 1997-2018 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR