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

memcpy sur le même buffer

8 réponses
Avatar
TSalm
Bonjour,

Je souhaiterais déplacer une chaîne de char.
Si je faisais quelquechose comme ça, est-ce que la mémoire serait
correctement liberée ?
______________________________________________
char* buff = malloc(sizeof(char)*200);
[...valorise buff...]
buff = buff + sizeof(char) * 50;
printf( buff );
free( buff );
______________________________________________


Ou alors, est-ce que copier le buffer dans le même buffer fonctionnerait ?

______________________________________________
char* buff = malloc(sizeof(char)*200);
[...valorise buff...]
memcpy( buff
, buff + sizeof(char) * 50
, sizeof(char) * 150
);
printf( buff );
free( buff );
______________________________________________


D'avance merci pour votre aide,
-TSalm

8 réponses

Avatar
Xavier Roche
Le 21/11/2011 22:22, TSalm a écrit :
free( buff );



Non, un free ne peut prendre que le pointeur original. L'allocateur ne
peut pas libérer le bloc si il n'a pas cette adresse.

Ou alors, est-ce que copier le buffer dans le même buffer fonctionnerait ?



Non. Utiliser memmove()

"memmove - copy bytes in memory with overlapping areas"
http://pubs.opengroup.org/onlinepubs/007904875/functions/memmove.html

[memcpy] "If copying takes place between objects that overlap, the
behavior is undefined."
http://pubs.opengroup.org/onlinepubs/009604599/functions/memcpy.html
Avatar
TSalm
free( buff );



Non, un free ne peut prendre que le pointeur original. L'allocateur ne
peut pas libérer le bloc si il n'a pas cette adresse.

Ou alors, est-ce que copier le buffer dans le même buffer
fonctionnerait ?



Non. Utiliser memmove()

"memmove - copy bytes in memory with overlapping areas"
http://pubs.opengroup.org/onlinepubs/007904875/functions/memmove.html

[memcpy] "If copying takes place between objects that overlap, the
behavior is undefined."
http://pubs.opengroup.org/onlinepubs/009604599/functions/memcpy.html




Je ne connaissais pas memcpy. Merci!
Avatar
TSalm
Le Mon, 21 Nov 2011 22:32:11 +0100, TSalm a écrit:

free( buff );



Non, un free ne peut prendre que le pointeur original. L'allocateur ne
peut pas libérer le bloc si il n'a pas cette adresse.

Ou alors, est-ce que copier le buffer dans le même buffer
fonctionnerait ?



Non. Utiliser memmove()

"memmove - copy bytes in memory with overlapping areas"
http://pubs.opengroup.org/onlinepubs/007904875/functions/memmove.html

[memcpy] "If copying takes place between objects that overlap, the
behavior is undefined."
http://pubs.opengroup.org/onlinepubs/009604599/functions/memcpy.html




Je ne connaissais pas memcpy. Merci!



Pardon, je voulais parler évidemment de memmove.
Merci.
Avatar
JKB
Le Mon, 21 Nov 2011 22:28:26 +0100,
Xavier Roche écrivait :
Le 21/11/2011 22:22, TSalm a écrit :
free( buff );



Non, un free ne peut prendre que le pointeur original. L'allocateur ne
peut pas libérer le bloc si il n'a pas cette adresse.



J'ajouterais que c'est parce que la plupart des allocateurs
utilisent la mémoire avant le pointeur retourné par malloc() pour
stocker tout un tas de choses dont la longueur de la zone allouée.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Samuel DEVULDER
Le 21/11/2011 22:22, TSalm a écrit :
Bonjour,

Je souhaiterais déplacer une chaîne de char.
Si je faisais quelquechose comme ça, est-ce que la mémoire serait
correctement liberée ?
______________________________________________
char* buff = malloc(sizeof(char)*200);
[...valorise buff...]
buff = buff + sizeof(char) * 50;
printf( buff );
free( buff );
______________________________________________



Ben non: la valeur de buff envoyée au free() ne correspond pas à celle
retournée par un malloc(). Pourquoi ne passes tu pas buff+50
directement au printf? Si tu préfères déclares un bloc après le malloc
et un pointeur représentant buff+50:

______________________________________________
char* buff = malloc(sizeof(char)*200);
[...valorise buff...]


{
char* buff_offset = buff+50;
foo(buff_offset);
}
free( buff );
______________________________________________



Nota: pour la simplicité on ne se préoccupe volontairement pas de
savoir si 50 signifie quelque chose (offsetof?) ou du fait que le
printf() n'utilise pas de chaine de format ce qui est mauvais si le
buff contient un %s ou un %d... Ici seul compte qu'il faut faire free()
de la valeur retournée par un malloc() (et pas valeur+50).


Ou alors, est-ce que copier le buffer dans le même buffer fonctionnerait ?

______________________________________________
char* buff = malloc(sizeof(char)*200);
[...valorise buff...]
memcpy( buff
, buff + sizeof(char) * 50
, sizeof(char) * 150
);
printf( buff );
free( buff );
______________________________________________



non memcpy() ne gère pas bien les buffers qui se chevauchent. Utiliser
memmove() à la place.

$ man memcpy
MEMCPY(3) NEWLIB MEMCPY(3)

NAME
6.8 `memcpy'--copy memory regions

SYNOPSIS
#include <string.h>
void* memcpy(void *OUT, const void *IN, size_t N);

DESCRIPTION
(...)
*If the regions overlap, the behavior is undefined.*

$ man memmove
MEMMOVE(3) NEWLIB MEMMOVE(3)

NAME
6.10 `memmove'--move *possibly overlapping* memory

sam.
Avatar
espie
In article ,
JKB wrote:
Le Mon, 21 Nov 2011 22:28:26 +0100,
Xavier Roche écrivait :
Le 21/11/2011 22:22, TSalm a écrit :
free( buff );



Non, un free ne peut prendre que le pointeur original. L'allocateur ne
peut pas libérer le bloc si il n'a pas cette adresse.



J'ajouterais que c'est parce que la plupart des allocateurs
utilisent la mémoire avant le pointeur retourné par malloc() pour
stocker tout un tas de choses dont la longueur de la zone allouée.



Plus forcement, aujourd'hui.

Pas mal d'allocateurs modernes sont dits "a puissance de 2", et vont
betement agreger les allocations de taille similaire dans une meme page
memoire (et retrouver les infos de taille directement a partir de l'adresse).

Le gros avantage par rapport aux trucs antiques, c'est qu'il y a beaucoup
moins d'overhead pour les petites allocations...

Par contre, ceux-ci vont raler des qu'on leur passe une adresse qui ne colle
pas avec ce qu'ils s'attendent a avoir. Typiquement, si j'ai alloue 128
octets, et que je passe une adresse a +64, l'allocateur va determiner la
page, trouver que celle-ci est censee contenir des blocs de 128 octets,
et raler tres fort parce que l'adresse n'est pas multiple de 128...
Avatar
erwan
(Marc Espie) écrivait :

Plus forcement, aujourd'hui.

Pas mal d'allocateurs modernes sont dits "a puissance de 2", et vont
betement agreger les allocations de taille similaire dans une meme page
memoire (et retrouver les infos de taille directement a partir de l'adresse).

Le gros avantage par rapport aux trucs antiques, c'est qu'il y a beaucoup
moins d'overhead pour les petites allocations...



Et limiter la fragmentation mémoire, qui sur certains programmes peut
avoir des effets désastreux (quand il reste 1Mo sous forme de 1000 blocs
discontinus de 1Ko par exemple).


--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
JKB
Le Tue, 22 Nov 2011 08:46:48 +0100,
écrivait :
(Marc Espie) écrivait :

Plus forcement, aujourd'hui.

Pas mal d'allocateurs modernes sont dits "a puissance de 2", et vont
betement agreger les allocations de taille similaire dans une meme page
memoire (et retrouver les infos de taille directement a partir de l'adresse).

Le gros avantage par rapport aux trucs antiques, c'est qu'il y a beaucoup
moins d'overhead pour les petites allocations...



Et limiter la fragmentation mémoire, qui sur certains programmes peut
avoir des effets désastreux (quand il reste 1Mo sous forme de 1000 blocs
discontinus de 1Ko par exemple).



Oui, alors ça, lorsqu'on arrive à avoir de la fragmentation mémoire,
c'est qu'on s'y est pris comme un pied et qu'on aurait dû utiliser
un allocateur spécial (quitte à faire avec mmap()). Les allocateurs
SLAB, qui allouent des blocs en puissance de deux, c'est
sympathique, mais ça a aussi des limites amusantes. Il faut les
dimensionner au plus juste si on veut être performant (pour ne pas
se retrouver avec des blocs de 10 octets qui bouffent en réalité 4 Ko
parce qu'il ne reste plus de blocs de taille adéquate...).

Personnellement, dans l'ordre, c'est malloc() (ptmalloc3), puis mmap(),
puis vraiment lorsque je suis contraint à la faire un SLAB...

Cordialement,

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr