Allocation dynamique de mémoire d'un tableau dans une fonction

Messages postés
4
Date d'inscription
dimanche 26 septembre 2004
Statut
Membre
Dernière intervention
13 février 2009
- - Dernière réponse : Arwen29
Messages postés
1
Date d'inscription
jeudi 10 avril 2003
Statut
Membre
Dernière intervention
17 janvier 2010
- 17 janv. 2010 à 16:32
Bonjour a tous,

mon problème est de pouvoir alloué la mémoire dynamiquement d'un tableau dans une fonction.
Voici mon problème niveau Code:
#include <stdio.h>
#include <stdlib.h>
#include "tri.h"

int main()
{
  int i= 5;
  int *tab;
  initialiserTableau(tab,i);
  printf("%d-%d\n",tab[1],tab[2]);
}

int initialiserTableau (int* tab, int n)
{
    tab = (int *) calloc( n,sizeof(int));
    tab[1]=2;
    tab[2]=0;
    printf("%d-%d\n",tab[1],tab[2]);
}

le tableau fait donc partie de la fonction main, puis l'allocation mémoire se fait dans la fonction initiliserTableau.

le problème est que lor du retour dans le main, le tableau ne possède pas les mêmes valeurs. Si quelqu'un a une idéé comment faire SVP??

Merci à tous!!
Afficher la suite 

6 réponses

Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
10
0
Merci
Bienvenue !

Avant tout, une remarque sur ton code : tu ne libères pas ton tableau alloué avec calloc. Il faut que tu utilises free.

Pour ta question...

Il faut que tu travaille tes pointeurs.

Tel qu'est ton code, tu déclares un int* dans ton main comme variable locale. Donc lors de l'exécution du main, un pointeur va être alloué (C'est plus une réservation qu'une allocation en fait) dans la pile (Sans initialisation de ce pointeur).

Puis tu appelles initialiserTableau en lui passant ce pointeur. En fait, tu lui passes une copie de ce pointeur non initialisé. Tu lui passe une adresse invalide en entrée.

Dans initialiserTableau, tu affectes ton argument, c'est à dire la copie du pointeur, avec une zone allouée avec calloc. En sortie de fonction, la copie est "supprimée", et tu perd l'adresse de ton tableau que tu ne peux plus libérer. Et quand ensuite tu testes ton tableau dans le main, tu regardes à une adresse qui n'a pas été initialisée. Passée par copie à initialiserTableau, elle n'a pas changée de valeur depuis le début du main.

Il faut que tu passe l'adresse du pointeur de ton main. (Ca à l'air lourd comme ça, mais quand tu auras compris, tu fera tout ça naturellement).

Il faut que ta fonction initialiser tableau prenne en argument un int**. Dans le main, tu passeras non pas ton pointeur, mais l'adresse de ton pointeur : &tab. Et lors de l'affectation à partir de calloc et de la manipulation, il faudra que tu déréférence ton pointeur (*tab).

Autre remarque, plus sur ton algo... On cherche souvent à éviter le principe de l'allocation dynamique réalisée par l'appelée. En général, c'est l'appelante qui alloue. Et si possible dans la pile (int tab[50]), pour de meilleurs perfs. Cela permet à l'appelante de gérer la mémoire de bout en bout : si on fait une allocation dynamique, on est sûr qu'il va falloire la libérer. Dans ton cas, on risque d'oublier la libération plus facilement. Reste que l'appelante ne sais pas forcément de combien de mémoire à besoin l'appelée... Dans ces cas là on fait comme tu as essayé de faire, ou on utilise un code d'erreur pour demander un nouvel appel avec un tampon plus gros, ou on propose un moyen de récupérer la taille nécessaire avant d'appeler la fonction.

Dernière remarque, compile avec les warnings si possible et occupe t'en. Au moins -Wall si tu utilises gcc. Il te dira notamment que ton main ne renvoie pas de valeur alors qu'il devrait renvoyer un int, le code de retour de ton programme.
Commenter la réponse de cs_rt15
Messages postés
4
Date d'inscription
dimanche 26 septembre 2004
Statut
Membre
Dernière intervention
13 février 2009
0
Merci
Bonsoir rt15, Merci de ta réponse.

Il est vrais que mon code n'est pas tout à fait correct, mais disont que  ce n'est qu'un petit bout de code expliquant mon problème. mais tu as raison, soyons rigoureux.

j'utilise bien GCC (sur débian). j'avais aussi pensé à utiliser le pointeur d'un pointeur (int**) puis mettre ladresse de mon pointeur (&tab) lors de l'appel à la fonction, mais gcc me génére une erreur.

voici le code rectifié:

01 #include <stdio.h>
02 #include <stdlib.h>
03 #include "tri.h"

04
05 int main()
06 {
07   int i= 5;
08   int * tab;
09   initialiserTableau(&tab,i);
10   printf("%d-%d\n",tab[1],tab[2]);
11   free (tab);
12   return 0;
13 }
14
15 void initialiserTableau (int** tab, int n)
16 {
17    tab = (int *) calloc( n,sizeof(int));
18    tab[1]=2;
19    tab[2]=0;
20    printf("%d-%d\n",tab[1],tab[2]);
21 }
Voici les erreurs généré par GCC:

$ gcc tri.c -o tri
tri.c: In function ‘main’:
tri.c:9: warning: passing argument 1 of ‘initialiserTableau’ from incompatible pointer type
tri.c: At top level:
tri.c:14: error: conflicting types for ‘initialiserTableau’
tri.h:3: error: previous declaration of ‘initialiserTableau’ was here
tri.c: In function ‘initialiserTableau’:
tri.c:16: warning: assignment from incompatible pointer type
tri.c:17: warning: assignment makes pointer from integer without a cast

Peut être y a t'il quelque chose qui m'ait échapé? ps: Ce code n'a pas de but particulier, c'est juste pour le sport. je suis tombé sur ce problème et je voudrais réussirà le résoudre.

Sinon tu me disais que dans la pratique, on dimensionne le tableau dans la fonction principale plutot que d'appeler une fonction qui elle dimensionne le tableau. Je prends note.

Merci encore!
Commenter la réponse de DJfewos971
Messages postés
4
Date d'inscription
dimanche 26 septembre 2004
Statut
Membre
Dernière intervention
13 février 2009
0
Merci
PS: j'ai fait une petite erreur, l'erreur de la ligne 14 concerne la ligne 15, et les warning 16 et 17 font référence aux lignes 17 et 18
Commenter la réponse de DJfewos971
Messages postés
4
Date d'inscription
dimanche 26 septembre 2004
Statut
Membre
Dernière intervention
13 février 2009
0
Merci
Pardon, j'ai répondu trop vite. je n'avais pas mis à jour le fichier .h

voici donc la véritable version du source:

#include <stdio.h>
#include <stdlib.h>
#include "tri.h"

int main()
{
  int i= 5;
  int * tab;
  initialiserTableau(&tab,i);
  printf("%d-%d\n",tab[1],tab[2]);
  free (tab);
  return 0;
}

int initialiserTableau (int** tab, int n)
{
    tab = (int **) calloc( n,sizeof(int));
    *tab[1]=2;
    *tab[2]=0;
    printf("%d-%d\n",tab[1],tab[2]);
}

cette fois ci je compile, mais l'ors de l'execution j'ai le droit à un segmentation default. On m'avait dis que ce genre d'erreur est provoqué l'orsque l'on tente de lire une zone mémoire dont notre processus n'a pas accées.

je pense m'approcher du but. je tiens au courant de mes évolutions. Si quelqu'un a d'autres idéés, qu'il n'hésite pas. bonne soirée!
Commenter la réponse de DJfewos971
Messages postés
1054
Date d'inscription
samedi 2 octobre 2004
Statut
Membre
Dernière intervention
9 juillet 2013
6
0
Merci
Salut
Tu alloues des int et pas des pointeurs sur des int! Donc il ne faut qu'une étoile pour le calloc.
Il faut faire aussi attention aux parenthèses qui sont ici indispensables...

(*tab)= (int* ) calloc( n,sizeof(int));
(*tab)[1]=2;
(*tab)[2]=0;
printf("%d-%d\n",(*tab)[1],(*tab)[2]);
A+
____________________________________________________________________________
Mon site internet :  
http://ImAnalyse.free.fr
Commenter la réponse de Pistol_Pete
Messages postés
1
Date d'inscription
jeudi 10 avril 2003
Statut
Membre
Dernière intervention
17 janvier 2010
0
Merci
Aaah! Merci, enfin un exemple clair et simple!
J'avais le même souci que DJfewos971, mais avec une chaîne de caractères.
Au cas où ça en aiderait certains, voici mon code (très légèrement) adapté:
void initialiserTableau (char** tab, int n)
{
    (*tab)= (char**) calloc( n,sizeof(char));
    (*tab)[0]='A';
    (*tab)[1]='B';
    (*tab)[2]='C';
    (*tab)[3]='D';
    (*tab)[4]='\0';
    printf("inside: %c-%c\n",(*tab)[1],(*tab)[2]);

}

int main()
{
  int i=5;
  char *tab;
  initialiserTableau(&tab,i); 
  printf("%s\n",tab);
  free (tab);
  return 0;
}


Voilà, ce qui m'a permis par la suite de faire une fonction de copie de chaînes.
Bonne journée à tous!
Commenter la réponse de Arwen29