Realloc ? comment faire ?

Fermé
www - 6 mai 2013 à 15:37
 www - 15 mai 2013 à 12:59
Bonjour,

Je dois développer un programme qui comporte un tableau
char *tablo[50];
.

Pour l'instant j'ai mis 50 mais c'est ridicule. En effet parfois j'aurais peut être 300 entrées et parfois 3...

Je souhaitais savoir si il était possible d'utiliser realloc afin de partir d'un tableau[1] et pouvoir l'agrandir au fur et a mesure...

En fait je parcours une boucle (20000 fois) et si un cas est vrai alors je dois ajouter dans le tableau de pointeurs.

Ai je été assez clair ?

Dans l'attente de vous lire.

www

4 réponses

garious Messages postés 1032 Date d'inscription vendredi 26 juin 2009 Statut Membre Dernière intervention 17 mars 2014 201
6 mai 2013 à 16:45
Bonjour,

Man 3 malloc ;). Tu auras ta réponse.

Cordialement,
1
Bonjour et merci pour ta réponse,

Cependant j'ai déjà lu de nombreuses explications avant de poser ma question.

Le problème est que je n'arrive même pas à faire un malloc...

Visual Studio (je developpe sous windows) me dit "L'expression doit être une valeur modifiable"...... ou bien "l'appel de fonction n'est pas autorisé dans une expression courante"
0
garious Messages postés 1032 Date d'inscription vendredi 26 juin 2009 Statut Membre Dernière intervention 17 mars 2014 201
8 mai 2013 à 20:39
Bonjour,

Euh sous Visual faut peut etre mettre les include de librairie du malloc ... #include <stdlib.h>

Cordialement,
0
Bonjour et merci pour ta réponse,

J'ai trouvé une "solution", mais je pense que ce n'est pas très propre :

Je déclare un char tablo[1]: et dans ma boucle j'incrémente une variable indextablo et a chaque fois je fais
tablo[indextablo] = (char*) malloc(strlen(an_id));
.

Cependant, je me sers de ce tableau dans une autre méthode et à la fin de mon programme j'ai une erreur qui me dit que tablo est corrompu... (ainsi je ne peux pas faire free(tablo);...)

Une idée ?

Cordialement
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
14 mai 2013 à 23:34
Faites-vous du C ou du C++ ? Car en C++, on n'utilise pas stdlib.h.
S'il s'agit de C :
Je déclare un char tablo[1]: et dans ma boucle j'incrémente une variable indextablo et a chaque fois je fais
Si tu fais char tablo[1]; ton tableau est déclaré. Pas besoin d'allocation.
Si tu souhaites allouer à l'exécution : char *tablo;
tablo=malloc(strlen(an_id)+1); /*on n'oublie pas la place pour le '\0'*/.
et en fin : free(tablo), tablo=NULL;
Cdlt,
0
nar6du14 Messages postés 459 Date d'inscription dimanche 27 décembre 2009 Statut Membre Dernière intervention 7 décembre 2013 64
Modifié par nar6du14 le 15/05/2013 à 03:44
va sur ce site c'est la reférence en c et c++: http://www.cplusplus.com/reference/

alors pour ta réponse. essaie ceci

#include <stdlib.h> // allocation de la mémoire
#include <stdio.h> // pour les printf et autres
#include <string.h> // meme si pas de fonctions de chaines de style c

typedef struct tableau tableau_t;

struct tableau
{

char **mon_tableau; // pointeur sur un tableau de chaines de caractère
int taille_du_tableau; // nombre total d'éléments dans mon tableau

};

void preserver_la_memoire( tableau_t *t, tableau_t *t1)
{
int i = 0, delta = (t->taille_du_tableau - t1->taille_du_tableau);
for( i = 0; i < t1->taille_du_tableau; i++ )
{
memset( t[ i ], t1[ i ], sizeof( char * ) );
}
for( i = 0; i < delta; i++)
{
memset( t[ i ], 0, sizeof( char * ) );
}
};

void initialisation_du_tableau( tableau_t *t ) // tjrs initialiser le tableau!!!!!!
{

t->mon_tableau = NULL;

t->taille_du_tableau = 0;

}

tableau_t * creer_tableau( )
{

tableau_t *t = ( tableau_t * )malloc( sizeof( tableau_t ) );

initialisation_du_tableau( t );

return t;

}

void liberer_tableau_de_caracteres( char ** h, int n_a_liberer )
{

int i = 0;

for( i = 0; i < n_a_liberer; i++ )
{

free( h[ i ] );

}
free( t->mon_tableau );

}

void ajouter_n_elements_a_mon_tableau( tableau_t *t, int n_elements )
{
tableau_t *t1 = t;

t->taille_du_tableau = t->taille_du_tableau + n_elements; // ancien taille + les n nouveaux

t->mon_tableau = ( char ** )malloc( t->taille_du_tableau * sizeof(char *) ); /*
une "n" nouvelles chaines de caractères à mon tableau */

preserver_la_memoire( t, t1 );

if( t1->taille != 0 )
{

liberer_tableau_de_caracteres( t->mon_tableau, t->taille_du_tableau );

}

}


**) liberer_tableau_de_caractères: est important car à chaque nouvelle allocation de mémoire, il faut libérer la précédente pour ne pas avoir de fuite de mémoire sinon "memory leak"

**) ajouter_n_elements_a_mon_tableau: ajoute simplement n nouvelles chaines de caractères à mon tableau.

***) initialisation_du_tableau initialise un tableau créé dynamiquement ou de façon automatique . Tjrs initialiser le tableau avant tout

****) creer_tableau crée un tableau dynamiquement et l'initialise par la suite


Comme tu le remarqueras, les deux premières fonctions sont très couteuses en temps. La solution serait d'allouer un plus grand espace dès le début et de l'agrandir au fur et à mesure des besoins.
0
nar6du14 Messages postés 459 Date d'inscription dimanche 27 décembre 2009 Statut Membre Dernière intervention 7 décembre 2013 64
Modifié par nar6du14 le 15/05/2013 à 03:46
pour le c++ c'est le meme logique malloc c'est "new" et "free" c'est "delete"
ce programme est très très long à mon gout0 Avec realloc c'est bon.
Faire simplement

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

typedef struct tableau tableau_t;

struct tableau
{
char ** tableau_de_chaine;
int length;
};

void release( tableau_t *t ) // à utiliser si chaque pointeur contient des elements sur la heap
{
int i = 0;
for( i = 0; i < t->length ; i++ )
{
free( t->tableau_de_chaine[ i ] );
}
free( t->tableau_de_chaine );
}

void add_new_elements( tableau_t *t, int n_elements )
{ t->length = t->length + n_elements;
t->tableau_de_chaine = ( char ** )realloc( t->taille_de_chaine, t->length );
}

avec ça, c'est plus simple
0
Bonjour à tous les deux et un grand merci pour vos réponses :

@fiddy : Je développe un code à partir d'API qui sont compatibles C++, mais j'ai repris une base du code developpé en C.
Je pense que cela est vraiment très mauvais ? mais ça m'a toujours étonné car tout fonctionne...
En effet j'ai bien compris pour tablo[1]; et j'ai donc choisi une autre solution:

A chaque fois que je rencontre un cas et qu'il faut incrémenter le tableau je fais comme ceci :
tablo[indextablo] = (char*) malloc(strlen(an_id));


Cependant je n'arrive pas à m'imaginer comment cela se passe dans le mémoire, meme si je fais un free dans une boucle à la fin du programme. nar6du14 indique que pour allouer de la memoire il faut avoir fait un free() du précedent. Je me rends compte que cette solution en fin de programme ne doit pas être correcte ?

@nar6du14 : Merci pour tes codes, mais surtout pour ces commentaires et explications très précieux !
0
J'ai été un peu vite,
@fiddy : quand vous dites "tablo=malloc(strlen(an_id)+1); /*on n'oublie pas la place pour le '\0'*/.
et en fin : free(tablo), tablo=NULL; "

J'ai essayé cette solution, mais je ne comprends pas comment ça se passe En effet, comment peut on utiliser des index tablo[1], tablo[2], tablo[3] etc... sachant que l'on alloue de la mémoire à un tablo ?

SI j'ai bien compris, il faudrait faire :

for (i=0; i<10;i++)
{
tablo=malloc(strlen(an_id)+1); //mais ou est la notion d'index la dedans ?
}
//ou récupere on le tableau d'id à ce moment ?


Cordialement
0
nar6du14 Messages postés 459 Date d'inscription dimanche 27 décembre 2009 Statut Membre Dernière intervention 7 décembre 2013 64
Modifié par nar6du14 le 15/05/2013 à 12:09
Si j'ai bien compris le problème que tu poses, tu cherches à faire un tableau dont la taille peut varier au fur et à mesure des besoins.

écrire char *tablo[ 50 ]; déclare un tableau de 50 pointeurs sur des chaines de caractères ( que ce soit d'un caractère ou plus );

donc si tu veux changer la taille de ton tableau, tu dois passer par un malloc qui allouera à la volée un espace contenant des pointeur sur des chaines de caractère et qui te renverra un pointeur sur cet espace autrement dit, malloc te renverra un pointeur sur des pointeurs de chaines de caractères : char **tab1 = ( char ** )malloc( taille * sizeof(char *) );

Il y'a certaines choses à savoir avec "free" et "realloc": tu ne peux pas utiliser ces deux fonctions sur des tableau crée de façon automatique ex: char *tab[ 50 ]; // faux!!!

par contre si le tableau a été crée avec "malloc" c'est possible d'utiliser par la suite "realloc" dessus et "free"

Quand tu utilises "realloc" tu n'as plus besoin d'utiliser "free" le système se charge de ça tout seul :) mais, une fois que tu n'as plus besoin du tableau tu dois le libérer

cependant, si tes pointeurs de chaines de caractère dans le tableau tab1 pointent chacun sur un espace mémoire alloué dynamiquement avec "malloc" tu dois libérer chacun de ces pointeurs avec "free" e.x si je fait

char *tab[ 50 ]; //allocation automatique à ne pas libérer avec "free"
tab[ 4 ] = ( char * )malloc( 4 ); //allocation d'une chaine de 4 caractères
memset( tab[ 4 ], 0, 4 ); //initialiser la chaine à 0 c'est à dire à une chaine de caractères vide

avant la fin du programme lorsque je n'aurai plus besoin du tableau, je doit utiliser "free" sur le
5 ième élément du tableau car cet élément pointe sur un espace mémoire alloué dynamique avec "malloc" au cas contraire j'ai une fuite de mémoire de 4 octets que je ne récupérerai
qu'au redémarrage du PC ( ou grâce à un logiciel de ramasse miette )

free( tab[ 4 ] );


En somme, retiens simplement que tout ce qui est alloué par "malloc" doit être impérativement libéré par "free" lorsqu'on en a plus besoin
0
Eh bien merci beaucoup nar6du14. J'ai bien lu tes explications, et j'ai trouvé ça plus clair !
Encore merci de passer du temps à m'expliquer tout ça.

Je pense que mon code est faux, car quand j'utilise un espion, même après un free, je retrouve plein de caracteres "bizarres". Mais j'espère que l'esprit est là :


ps : je travaille avec MEM_alloc et MEM_free qui fait exactement la même chose, d'après le guide des API.



char **tablo; //déclaration
tablo = (char**) MEM_alloc(sizeof(char)); //ici j'ai décidé de faire un malloc pour "initialiser le tableau"


//ici une boucle avec plein de conditions que je ne vais pas mettre pour un souci de clarté.


//SI on rentre dans la condition alors : 
tablo[indextablo] = (char*) MEM_alloc(strlen(an_id)); //d'après ton explication je pense que cette ligne est "mauvaise" mais je ne vois pas quoi mettre a la place de "strlen(an_id)".


strcpy(tablo[indextablo], an_id);


indextablo = indextablo+1;


//APPEL A UNE FONCTION QUI VA CREER UN TABLEAU A PARTIR DE "TABLO"


//fin du main :

for (s=0; s<indextablo; s++)
 {
                 MEM_free(tablo[s]);//faut il faire comme ceci ou bien un free(tablo) suffit ?
 } 
 



En tout cas merci pour ta patience
0