Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

comprendre malloc et realloc

47 réponses
Avatar
heron
Bonjour

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

En fait, je comprends l'utilit=E9 de malloc dans le sens ou la
r=E9servation de la m=E9moire pour un tableau peut se faire en cours
d'ex=E9cution...

Pour la saisie de texte, je voudrais savoir s'il serait possible de
saisir une cha=EEne de caract=E8re variable avec fgets ? Je pense beaucoup
=E0 utiliser realloc.

Par exemple : je r=E9serve de la m=E9moire pour un pointeur vers une
adresse de type caract=E8re, pour 1 ou 2 caract=E8res et =E0 je demande =E0
l'utilisateur de saisir du texte. A chaque saisie, je r=E9serve la place
pour un caract=E8re suppl=E9mentaire en m=E9moire avec realloc, c'est
faisable? Bizarement, je ne trouve aucun code qui correspond =E0 ce que
je recherche sur le net.

Ca ressemble =E0 peu pr=E8s, mais =E7a 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=E8re :
est-ce que =E9crire char* chaine =3D 0 et char *chaine =3D 0 revient =E0 la
m=EAme chose?

Merci,

10 réponses

1 2 3 4 5
Avatar
Erwan David
Marc écrivait :

Marc Espie wrote:

[realloc: capacite+=constante vs capacite*=constante]
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...



Tu es peut-être un peu pessimiste. Si on fait un malloc(1) suivi de
p=realloc(p,i++) en boucle et qu'on vérifie à quelles étapes realloc
renvoie un pointeur différent, avec beaucoup d'allocateurs, on constate
une progression géométrique collant précisément à ce capacite*=constante.
Ce qui ne veut pas dire qu'il faut compter sur ce comportement, il vaut
effectivement mieux gérer soi-même le doublement de capacité en supposant
que realloc n'est pas plus efficace que malloc+memcpy+free.



Attention là tu viens de foutre en l'air ton traitement d'erreur...

si ton realloc te renvoie NULL, tu as en plus une belle fuite mémoire
car tu as perdu l'ancien pointeur, mais la zone n'a pas été désallouée.
C'est un des dangers de realloc...

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
espie
In article <hsn5ko$ica$, Marc wrote:
Marc Espie wrote:

[realloc: capacite+=constante vs capacite*=constante]
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...



Tu es peut-être un peu pessimiste. Si on fait un malloc(1) suivi de
p=realloc(p,i++) en boucle et qu'on vérifie à quelles étapes realloc
renvoie un pointeur différent, avec beaucoup d'allocateurs, on constate
une progression géométrique collant précisément à ce capacite*=constante.
Ce qui ne veut pas dire qu'il faut compter sur ce comportement, il vaut
effectivement mieux gérer soi-même le doublement de capacité en supposant
que realloc n'est pas plus efficace que malloc+memcpy+free.



Ah oui, tiens, c'est une consequence logique du fonctionnement des allocateurs
modernes. Par contre, dans l'enorme majorite des cas, ce comportement va
s'arreter au-dela d'une certaine taille (les allocateurs "par puissance de 2"
ont generalement un seuil au-dessus duquel ils font directement appel a mmap)
Avatar
Xavier Roche
Marc Espie a écrit :
Tu es peut-être un peu pessimiste. Si on fait un malloc(1) suivi de
p=realloc(p,i++) en boucle et qu'on vérifie à quelles étapes realloc
renvoie un pointeur différent, avec beaucoup d'allocateurs, on constate
une progression géométrique collant précisément à ce capacite*=constante.





Ce n'est pas vrai sous Windows, de mémoire, avec la libc Microsoft. Cela
peut entrainer des bugs de perfs assez gigantesques, si on compte sur
l'effet géométrique de l'allocateur, car celui-ci n'existe pas toujours.
Avatar
espie
In article <hsog6f$e9f$,
Xavier Roche wrote:
Marc Espie a écrit :
Tu es peut-être un peu pessimiste. Si on fait un malloc(1) suivi de
p=realloc(p,i++) en boucle et qu'on vérifie à quelles étapes realloc
renvoie un pointeur différent, avec beaucoup d'allocateurs, on constate
une progression géométrique collant précisément à ce




capacite*=constante.

Ce n'est pas vrai sous Windows, de mémoire, avec la libc Microsoft. Cela
peut entrainer des bugs de perfs assez gigantesques, si on compte sur
l'effet géométrique de l'allocateur, car celui-ci n'existe pas toujours.



Je vais faire mon persifleur, alors... la derniere fois que j'ai vu un
allocateur sans puissances de 2 sous un unixoide, ca devait etre il y a une
bonne dizaine d'annees. Tout le monde savait deja que c'etait mauvais en
termes de perfs pour la plupart des appli (et qu'une appli jouant avec
sa memoire de facon intensive allait tres vite bouffer toute la memoire
disponible pour elle sur le systeme, donc soit faire ramer tout le monde,
soit se faire tuer par depassement de son rusage).

Si microsoft n'a toujours pas compris ca (enfin, je pense qu'ils ont compris,
mais doit encore y avoir une histoire de sacro-sainte compatibilite binaire
a la noix), ca expliquerait en grande partie pourquoi ce systeme est
monstrueusement gourmand en occupation memoire: les allocateurs sous-optimaux,
ca a une nette tendance a fractionner la memoire a la vitesse grand V.

Bien joue les mecs...
Avatar
Antoine Leca
heron écrivit :
Fgets place les données sur le "tas" (heap).



Non. fgets() place les données reçues dans le tableau passé en argument
(ainsi que sa taille réelle).
Et c'est la responsabilité du programmeur que d'avoir alloué ce tableau
auparavant, que ce soit avec une allocation statique (sur la pile)
char Txt[5] ;


ou dynamique (sur le tas)
Txt = ÞÞÞÞalloc()

("ÞÞÞÞ" pouvant être "m", "c", "re").

La logique de C est de séparer le plus nettement possible d'un côté les
algorithmes qui utilisent les objets, et de l'autre la gestion de
mémoire, dont l'allocation des dits objets.
fgets() et les fonctions en général s'occupent du premier côté ;
malloc(), calloc(), realloc(), free(), plus les mots clés static et auto
et plus généralement la syntaxe des déclarations d'objets, sont
quasiment les seuls qui s'occupent de la gestion de la mémoire.


Antoine
Avatar
heron
On May 17, 8:48 am, Antoine Leca wrote:
heron écrivit :

> Fgets place les données sur le "tas" (heap).

Non. fgets() place les données reçues dans le tableau passé en argu ment
(ainsi que sa taille réelle).
Et c'est la responsabilité du programmeur que d'avoir alloué ce table au
auparavant, que ce soit avec une allocation statique (sur la pile)>     char Txt[5] ;

ou dynamique (sur le tas)
      Txt = ÞÞÞÞalloc()

("ÞÞÞÞ" pouvant être "m", "c", "re").

La logique de C est de séparer le plus nettement possible d'un côté les
algorithmes qui utilisent les objets, et de l'autre la gestion de
mémoire, dont l'allocation des dits objets.
fgets() et les fonctions en général s'occupent du premier côté ;
malloc(), calloc(), realloc(), free(), plus les mots clés static et aut o
et plus généralement la syntaxe des déclarations d'objets, sont
quasiment les seuls qui s'occupent de la gestion de la mémoire.

Antoine



très clair,
merci (j'en redemande)
Avatar
heron
Je ne vois pas la différence entre :
...
cnt = 0 ;
cnt++ ;
numbers = (int *) realloc(numbers, cnt * sizeof(int) ) ;
...
et
...
i = 0 ;
++i ;
chaine = realloc(chaine, (i+1) * sizeof(char) ) ;

Dans le premier cas, lors de la première reallocation, cnt = 1 alors 1
* 2 = 2 ou 1 * 4 = 4 soit la place pour un et un seul entier suivant.
Dans le second cas, au premier appel, i = 2 alors 2 * 1 = 2 soit la
place pour 2 autres caractères.

Est-ce que ce qui différencie la variable cnt et la variable int est
le type de données qu'elles se chargent de réserver? Pour un nombre
entier, il s'agirait alors juste d'un nombre entier supplémantaire
alors que pour la variable caractère il y aurait également le
caractère de fin de tableaux de caractère '' ?

Plus haut dans cette discussion, il est question de savoir si c'est
mieux d'additionner que de multiplier mais je ne suis pas encore à ce
niveau pour me poser ce genre de question. Je voudrais juste être sûre
de comprendre les bases.
Avatar
Samuel DEVULDER
heron a écrit :
Je ne vois pas la différence entre :
...
cnt = 0 ;
cnt++ ;
numbers = (int *) realloc(numbers, cnt * sizeof(int) ) ;
...
et
...
i = 0 ;
++i ;
chaine = realloc(chaine, (i+1) * sizeof(char) ) ;




Normal! il n'y en a pas.. C'est bonnet-blanc ou blanc-bonnet, au choix.
Il y a juste un "+1" sur i peut-être pour l'histoire du final, mais
ca ne change rien.

sam.
Avatar
Antoine Leca
heron écrivit :
Je ne vois pas la différence entre :
...
cnt = 0 ;
cnt++ ;
numbers = (int *) realloc(numbers, cnt * sizeof(int) ) ;
...
et
...
i = 0 ;
++i ;
chaine = realloc(chaine, (i+1) * sizeof(char) ) ;

Dans le premier cas, lors de la première reallocation, cnt = 1 alors 1
* 2 = 2 ou 1 * 4 = 4 soit la place pour un et un seul entier suivant.



Attention, cela fait _ou défait_ la place pour un seul entier _tout
court_ ; donc si avant le realloc() numbers était un pointeur vers
l'espace pour dix entiers, après le realloc tu as _perdu_ les neuf
derniers, d'accord ?

Dans le second cas, au premier appel, i = 2 alors 2 * 1 = 2 soit la
place pour 2 autres caractères.



Idem, pas deux _autres_ mais deux _en tout_.


Antoine
Avatar
Samuel DEVULDER
Antoine Leca a écrit :

Attention, cela fait _ou défait_ la place pour un seul entier _tout
court_ ; donc si avant le realloc() numbers était un pointeur vers
l'espace pour dix entiers, après le realloc tu as _perdu_ les neuf
derniers, d'accord ?


../..

Idem, pas deux _autres_ mais deux _en tout_.



Arf.. Tres bonne remarque, j'avais même pas vu que Heron pouvait penser
que realloc travaillait en relatif "augmentait" ou "diminuais" la zone
mémoire du pointeur. Ca ne m'etait jammais venu à l'esprit que quelqu'un
imagine cela (le manpage est clair au sujet de realloc).

Heron: la taille passée à realloc() est une taille absolue (comme
malloc), pas relative! C'est super important à comprendre!

sam (Tapons ou Héron? Héron petit, pas Tapons :) )
1 2 3 4 5