Aller au contenu

%REALLOC

Redimensionner un bloc de mémoire

Change la taille d'un bloc de mémoire déjà réservé, en conservant son contenu, et renvoie le pointeur à utiliser ensuite.

Syntaxe

%REALLOC(pointeur : taille)
pointeur
Le pointeur renvoyé par un précédent %ALLOC ou %REALLOC.
taille
La nouvelle taille du bloc, en octets.
Résultat
Un pointeur sur le bloc redimensionné. Il peut être différent de l'ancien : il faut toujours utiliser la valeur renvoyée.

À quoi ça sert

Quand on lit un nombre inconnu de lignes, on démarre avec un petit bloc et on l'agrandit au fur et à mesure. %REALLOC garde les données déjà présentes, sans les recopier à la main.

Exemple 1 : Agrandir puis réduire

**free
// %REALLOC : agrandir une zone deja reservee sans perdre son contenu.
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-s p pointer;
dcl-s ancien pointer;
dcl-s villes char(12) dim(50) based(p);
dcl-s nb int(10);
dcl-s i int(10);

// Au depart, place pour 2 villes.
nb = 2;
p = %alloc(nb * %size(villes(1)));
villes(1) = 'Montpellier';
villes(2) = 'Lyon';

// Il en faut 4 : on agrandit, les 2 premieres restent en place.
nb = 4;
ancien = p;
p = %realloc(p : nb * %size(villes(1)));
snd-msg 'Adresse changee ? ' + %char(p <> ancien);
villes(3) = 'Brest';
villes(4) = 'Nantes';

for i = 1 to nb;
  snd-msg 'Ville ' + %char(i) + ' : [' + villes(i) + ']';
endfor;

// On reduit a 1 ville : seule la premiere est conservee.
nb = 1;
p = %realloc(p : nb * %size(villes(1)));
snd-msg 'Apres reduction : [' + villes(1) + ']';

dealloc(n) p;

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Adresse changee ? 1
Ville 1 : [Montpellier ]
Ville 2 : [Lyon        ]
Ville 3 : [Brest       ]
Ville 4 : [Nantes      ]
Apres reduction : [Montpellier ]

Le bloc démarre à 2 villes et passe à 4 : Montpellier et Lyon sont toujours là, on ajoute Brest et Nantes. La ligne « Adresse changee ? » vaut 1 : le bloc agrandi a été déplacé. En réduisant à 1 ville, seule la première est conservée.

Exemple 2 : Partir d'un pointeur nul

**free
// %REALLOC : un pointeur nul donne une premiere reservation, comme %ALLOC.
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-s p pointer;
dcl-s note char(20) based(p);

snd-msg 'Avant : pointeur nul ? ' + %char(p = *null);
p = %realloc(p : %size(note));
snd-msg 'Apres : pointeur nul ? ' + %char(p = *null);
note = 'Reservation';
snd-msg 'Contenu : [' + note + ']';
dealloc(n) p;

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Avant : pointeur nul ? 1
Erreur : RNQ0426 - (C G D F) Erreur lors d'une opération de gestion de mémoire.

Un pointeur nul n'est pas accepté : le programme s'arrête avec RNQ0426, erreur de gestion de mémoire.

Le piège

Le pointeur de départ doit venir de %ALLOC. Avec un pointeur nul, %REALLOC ne réserve rien et s'arrête avec RNQ0426 (exemple 2). Pour la première réservation, utilisez %ALLOC.

Réaffectez toujours le résultat au pointeur (p = %realloc(p : ...)) : l'adresse du bloc change (exemple 1), et l'ancienne ne doit plus servir.