IV. c_memmove▲
IV-A. Prototype▲
void
*
c_memmove (
void
*
dest, const
void
*
src, c_size_t n);
IV-B. Description et comportement▲
Le nom de cette fonction peut porter à confusion, car, elle ne déplace pas des données, mais copie tout comme le fait c_memcpy à quelques détails près !
La fonction c_memmove est à double usage ! Son comportement est d'une part identique à celui de la fonction c_memcpy si les blocs mémoire sont disjoints donc qui ne se chevauchent pas. Là où les deux fonctions diffèrent l'une de l'autre, c'est que la fonction c_memmove permet également de prendre en charge des blocs qui se recouvrent partiellement donc qui se chevauchent !
La fonction c_memmove copie donc n octets de l'adresse src vers l'adresse dest et retourne l'adresse dest !
IV-C. Algorithme▲
Voici un algorithme possible pour la fonction c_memmove :
algorithme
fonction c_memmove (dest:générique, src:générique, n:entier):générique
début
si src inférieur ou égal à dest alors
t1 <- src + (n - 1)
t2 <- dest + (n - 1)
tant que n <- n - 1 faire
dest[t2] <- src[t1]
t1 <- t1 - 1
t2 <- t2 - 1
ftant
sinon
c_memcpy (dest, src, n)
fsi
retourne dest
fin
lexique
dest : générique : Zone mémoire de destination d'un type quelconque.
src : générique : Zone mémoire source d'un type quelconque.
n : entier : Longueur de la copie.
t1 : entier : Variable de déplacement dans la zone mémoire src.
t2 : entier : Variable de déplacement dans la zone mémoire dest.
L'algorithme est ici un peu plus long que les autres, car il faut gérer deux comportements, mais rien d'insurmontable. Dans la condition logique, nous testons le chevauchement des zones mémoire. Si le début de l'adresse src est inférieur au début de l'adresse dest, il y a un risque de chevauchement des données et donc, pour éviter de corrompre la copie des octets, nous commençons par la fin de la copie de longueur n !
Dans cette boucle, nous parcourons un à un les octets de l'adresse src en partant de la fin…
Pour calculer la fin des adresses, on ajoute tout simplement la valeur de l'argument n à l'adresse de la zone à calculer puis on soustrait 1 pour débuter directement à la bonne adresse !
… puis on les copie dans la zone d'adresse dest. À chaque tour de boucle, il ne faut pas non plus oublier de décrémenter les variables qui permettent le parcours (oui ici on décrémente, car nous partons de la fin jusqu'au début donc à l'envers).
Dans la seconde partie de la condition principale, nous appelons tout simplement la fonction c_memcpy, car le comportement est alors identique, cela évite de programmer inutilement vu que nous disposons déjà de cette fonction.
On termine la fonction en retournant l'adresse dest.
Complexité temporelle dans le pire des cas : |
---|
Parcours simple de la boucle n fois: complexité en O(n) |
IV-D. Implémentation▲
void
*
c_memmove (
void
*
dest, const
void
*
src, c_size_t n)
{
char
*
p_dest =
dest;
const
char
*
p_src =
src;
if
(
p_src <=
p_dest)
{
p_dest +=
n -
1
;
p_src +=
n -
1
;
while
(
n--
)
{
*
p_dest--
=
*
p_src--
;
}
}
else
{
c_memcpy (
dest, src, n);
}
return
dest;
}
L'implémentation est à peu près identique à l'algorithme sauf qu'elle est adaptée aux pointeurs. Nous ne disposons donc pas de variables de parcours, mais nous travaillons directement sur les pointeurs !
IV-E. Tests▲
#include "c_string.h"
#include <stdio.h>
int
main (
void
)
{
char
tab1 [] =
"
abcdefghijklmno
"
;
printf (
"
tab1 = %s
\n
"
, tab1);
c_memmove (
tab1 +
5
, tab1 +
2
, 7
);
printf (
"
tab1 = %s
\n
"
, tab1);
return
0
;
}
Dans cet exemple vous pouvez effectivement observer un chevauchement partiel des blocs sur lesquels la fonction doit travailler et dans ce cas, elle va copier les n octets en commençant par la fin, voyons le résultat sur la console :
tab1 =
abcdefghijklmno
tab1 =
abcdecdefghimno
Process returned 0
(
0x0
) execution time : 0
.015
s
Press any key to continue
.
Nous avons donc fait copier 7 octets en commençant par la fin, ce qui nous fait partir du bloc à l'adresse tab1 + (2 + 7) pour commencer à remplir à l'adresse tab1 + (5 + 7) et pour arriver en fin d'écriture à l'adresse tab1 + 5 ! Voici un schéma permettant de mieux visualiser le fonctionnement dans ce cas précis :