comprendre malloc et realloc

Le
heron
Bonjour

Je débute avec le C depuis quelques mois à mon rhytme. J'arrive au
chapitre de l'allocation dynamique. J'ai abordé les tableaux uni et
multidimensionnels, les pointeurs, les fonctions.

En fait, je comprends l'utilité de malloc dans le sens ou la
réservation de la mémoire pour un tableau peut se faire en cours
d'exécution

Pour la saisie de texte, je voudrais savoir s'il serait possible de
saisir une chaîne de caractère variable avec fgets ? Je pense beaucoup
à utiliser realloc.

Par exemple : je réserve de la mémoire pour un pointeur vers une
adresse de type caractère, pour 1 ou 2 caractères et à je demande à
l'utilisateur de saisir du texte. A chaque saisie, je réserve la place
pour un caractère supplémentaire en mémoire avec realloc, c'est
faisable? Bizarement, je ne trouve aucun code qui correspond à ce que
je recherche sur le net.

Ca ressemble à peu près, mais ça ne marche pas :
http://www.cppfrance.com/forum/sujet-RECUERATION-CHAINE-CARACTERE-TAILLE-VA=
RIABLE-STDIN_1405662.aspx

Autre question sans lien avec la première :
est-ce que écrire char* chaine = 0 et char *chaine = 0 revient à la
même chose?

Merci,
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 5
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
espie
Le #22119081
In article heron
Par exemple : je réserve de la mémoire pour un pointeur vers une
adresse de type caractère, pour 1 ou 2 caractères et à je demande à
l'utilisateur de saisir du texte. A chaque saisie, je réserve la place
pour un caractère supplémentaire en mémoire avec realloc, c'est
faisable? Bizarement, je ne trouve aucun code qui correspond à ce que
je recherche sur le net.



C'est faisable, mais personne ne le fait parce que ca n'est pas efficace.
realloc a un cout non nul, du coup, on en fait moins.

Le classique, c'est de doubler la taille du tampon a chaque fois.
heron
Le #22119231
Pourquoi ce code ne renvoie pas le texte saisie?

#include #include
int main(void)
{
char* chaine = 0 ;
char c ;
int i = 0 ;

printf("Tapez une phrase :") ;

while ( (c = getchar() ) && c != EOF )
{
++i ;
chaine = realloc(chaine, (i+1) * sizeof(char) ) ;
chaine[i-1] = c ;
chaine[i] = 0 ;
}

printf("nVous avez entre : '%s'n", chaine) ;
free(chaine) ;

return 0 ;
}

simple question : char* chaine et char *chaine c'est différent?
heron
Le #22119261
Ce que je souhaiterais avec des caractères :

#include #include
int main(void)
{
int input, n ;
int cnt = 0 ;
int *numbers = NULL ;

do
{
printf("nEnter an integer value (enter 0 to stop) : ") ;
scanf("%d", &input) ;
cnt++ ;
numbers = (int *) realloc (numbers, cnt * sizeof(int) ) ;

if ( numbers == NULL )
{
puts("Error (re)allocating memory") ;
exit(1) ;
}

numbers[cnt-1] = input ;

} while ( input != 0 ) ;

printf("nNumbers entered : ") ;

for ( n = 0 ; n < cnt-1 ; n++ )
printf("n%d ", numbers[n]) ;

printf("nn") ;
return 0 ;
}
Eric Dorino
Le #22119251
On Fri, 14 May 2010 17:08:03 -0700, heron wrote:

Bonjour

Pourquoi ce code ne renvoie pas le texte saisie?



Il le renvoie lorsque une fin de fichier est lue.


#include #include
int main(void)
{
char* chaine = 0 ;
char c ;
int i = 0 ;

printf("Tapez une phrase :") ;

while ( (c = getchar() ) && c != EOF ) {



while ( (c = getchar() ) && c != EOF && c != 'n' ) {
termine la boucle en fin de ligne et affiche le texte.

++i ;
chaine = realloc(chaine, (i+1) * sizeof(char) ) ; chaine


[i-1] = c ;
chaine[i] = 0 ;
}

printf("nVous avez entre : '%s'n", chaine) ; free(chaine) ;

return 0 ;
}

simple question : char* chaine et char *chaine c'est différent?



De le même manière que "bonnet blanc" et "blanc bonnet" sont
différents :-)
Pour le compilateur: non.

--
Eric
heron
Le #22119271
>    char c ;

>    while ( (c = getchar() ) &&  c != EOF ) {

        while ( (c = getchar() ) &&  c != EOF  && c != 'n' ) {
termine la boucle en fin de ligne et affiche le texte.

> simple question : char* chaine et char *chaine c'est différent?

De le même manière que "bonnet blanc" et "blanc bonnet" sont
différents :-)
Pour le compilateur: non.

--
Eric



Il me semblait que c devait être déclaré comme int pour agir dans le
buffer avec
while ( c = getchar() != 'n' && c != EOF )
;
je pense que c'est parce que EOF renvoie -1 ...

Merci de l'info pour char* et char *
Eric Dorino
Le #22119601
On Fri, 14 May 2010 18:19:07 -0700, heron wrote:


Il me semblait que c devait être déclaré comme int pour agir dans le
buffer avec



Effectivement.

while ( c = getchar() != 'n' && c != EOF )
;



Attention à la priorité des opérateurs: vous voulez certainement
while ( ( c = getchar() ) != 'n' && c != EOF )

je pense que c'est parce que EOF renvoie -1 ...



Plus exactement, getchar() renvoie un int.


Merci de l'info pour char* et char *



--
Eric
espie
Le #22119591
Tant qu'a expliquer... meme si c'est de la FAQ.

Le type char est exactement assez grand pour contenir tous les codes de
caracteres.

Du coup, la fin de fichier ne "rentre" pas: c'est un code en plus (et sur
beaucoup d'OS, il n'y a pas de code specifique stocke sur le disque pour
indiquer la fin de fichier, c'est la taille du fichier qui est marquee "quelque
part" dans le repertoire).

En C, on utilise simplement un type un peu plus grand, a savoir int, qui
permet:
- de stocker tous les codes de caracteres sans perte
- de rajouter un code supplementaire, qu'on appelle EOF.

Attention: EOF vaut souvent -1, mais je ne crois pas que ca soit meme
rendu oblige par la norme. Suffit que ca soit une valeur distincte de
tous les codes de caracteres (et c'est le plus souvent -1 parce que sinon du
code mal ecrit va peter, et vous me croirez ma bonne dame, mais du code mal
ecrit il y en a, et souvent les gens font passer la compatibilite avant le
reste...)

Il y a pas mal de details scabreux, mais au final, cote typage:

int char_ou_eof = fgetc(f);
if (char_ou_eof != EOF) {
char c = char_ou_eof;
}

doit avoir l'effet attendu sur tous les OS: lire "quelque chose" d'un fichier,
reperer un EOF, et stocker ce quelque chose sous forme de caractere si on n'est
pas arrive en fin de fichier.
Jean-Marc Bourguet
Le #22119901
(Marc Espie) writes:

Attention: EOF vaut souvent -1, mais je ne crois pas que ca soit meme
rendu oblige par la norme.



Expression constante entière négative et je n'ai pas l'impression que POSIX
impose plus.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
heron
Le #22120131
Pour la saisie avec allocation dynamique de caractères avec getchar()
comme dans le code plus haut ou de nombres entiers avec scanf, je
trouve que ça rend les choses plus simples. Est-ce que pour la saisie
d'une chaîne de caractère, on peut procéder avec fgets au lieu de
getchar() ? Jusque là, fgets était le plus souvent employé.

Mais pour reprendre Marc plus haut

C'est faisable, mais personne ne le fait parce que ca n'est pas efficace.
realloc a un cout non nul, du coup, on en fait moins.



L'allocation dynamique dans la saisie d'une chaîne de caractères de
longeur variable ou d'entier avec scanf n'est pas efficace dans le
sens ou il y a moins de sécurité ?

Le classique, c'est de doubler la taille du tampon a chaque fois.



Est-ce que c'est parce qu'un dépassement de buffer peut se produire
avec l'allocation dynamique. Je ne vois pas très bien comment car
getchar() ne lit qu'un seul caractère à chaque appel. Dans le premier
post, je pensais à fgets, je pense que c'est pour fgets que ce n'est
pas efficace. Je n'ai pas réfléchi à comment y arriver. Mais est-ce
que ce n'est pas efficace parce le code est trop compliqué ou parce
qu'il y a moins de sécurité?
espie
Le #22120301
In article heron
L'allocation dynamique dans la saisie d'une chaîne de caractères de
longeur variable ou d'entier avec scanf n'est pas efficace dans le
sens ou il y a moins de sécurité ?



Non, je parle d'efficacite au sens algorithmique.

Le classique, c'est de doubler la taille du tampon a chaque fois.



Est-ce que c'est parce qu'un dépassement de buffer peut se produire
avec l'allocation dynamique. Je ne vois pas très bien comment car
getchar() ne lit qu'un seul caractère à chaque appel. Dans le premier
post, je pensais à fgets, je pense que c'est pour fgets que ce n'est
pas efficace. Je n'ai pas réfléchi à comment y arriver. Mais est-ce
que ce n'est pas efficace parce le code est trop compliqué ou parce
qu'il y a moins de sécurité?



Non, aucun rapport avec la securite.

ce dont je parle, c'est les tampons de taille variable.

schematiquement, et sans controle d'erreur (tous les malloc doivent etre
verifies, en general).

T *t;
size_t size; /* taille utilisee */
size_t capacity; /* taille disponible */

void
init()
{
capacity = N; /* a choisir */
t = malloc(sizeof(T) * N);
size = 0;
}

void
add_element(T e)
{
if (size > capacity)
grow_array();
t[size++] = e;
}

void grow_array()
{
capacity *= 2;
t = realloc(t, sizeof(T) * capacity);
}


(ce que tu proposes, c'est de faire capacity += constante dans grow_array).

Analyse classique algorithmique:
si tu fais croitre la capacite de +N a chaque fois, tu vas gaspiller la place
de N/2 elements en moyenne, et tu vas faire size/N reallocations.

Si tu fais croitre la capacite du tableau * 2 a chaque fois, tu vas gaspiller
la place de 1/4 size elements en moyenne, et tu vas faire log2(size)
reallocations.


On prefere le 2e schema dans l'enorme majorite des applications. Sur la
plupart des OS, le plus souvent, il n'y a "pas de place" apres ton tableau,
et realloc revient donc a allouer un nouveau tableau et tout copier... en
general, la place memoire coute peu cher, mais la bande passante vers la
memoire domine largement le temps d'execution: on s'en fout de gaspiller un
peu, mais on veut faire le moins possible de copies inutiles.

Pour des chaines de caracteres, un idiome classique, c'est d'avoir un
tampon global qui va croitre avec l'idiome ci-dessus, et une fois lue une
chaine qui t'interesse, en general, tu ne stockes que les bouts qui
t'interessent, donc soit tu parses au vol, soit tu fais du strdup() a partir
du tampon... -> au final tu gaspilles un peu de place dans un seul tampon,
tu as tes donnees qui sont copiees au plus juste, et ca marche tres bien...
Publicité
Poster une réponse
Anonyme