3 votes

c memcpy struct par valeur

J'essaie simplement de copier une structure vers une autre (copie par valeur, PAS par référence). Voici un code entièrement fonctionnel

/* memcpy example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE (80*sizeof(char))

typedef struct {
    char* name;
} person;

int main ()
{
  person p1;
  p1.name = (char*) malloc( SIZE );

  person p2;
  p2.name = (char*) malloc( SIZE );

  // set p1
  strcpy(p1.name, "John");

  // copy p1 > p2
  memcpy ( &p2, &p1, SIZE );

  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  // change p1 only
  printf("Changing p1.name\n");
  strcpy(p1.name, "ONLY p1.name Changed");

  // now, why did p2 change?
  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  free(p1.name);
  free(p2.name);

  return 0;
}

Voici un violon http://cpp.sh/57skb

Ce code produit

p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: ONLY p1.name Changed (0x791b3cdd6280)

La sortie attendue serait

p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)

Question : pourquoi p2 changement ?

Notez que faire la même chose sans structure fonctionne comme prévu : http://cpp.sh/6qevd

3voto

Eraklon Points 4053

Quand vous faites cette copie, les deux structures name auront la même valeur et pointeront donc vers le même emplacement mémoire. Votre code ne le montre pas puisque vous n'imprimez pas correctement la valeur du pointeur. Essayez ceci pour vérifier qu'ils sont bien identiques

  printf ("p1.name: %s (%p)\n", p1.name, p1.name );
  printf ("p2.name: %s (%p)\n", p2.name, p2.name );

Sortie

p1.name: John (0x3ee8d60)
p2.name: John (0x3ee8d60)

p2 ne change pas après strcpy(p1.name, "ONLY p1.name Changed"); . Tout simplement p2.name pointe également vers cette nouvelle chaîne.

2voto

Doug Simpson Points 41

Si vous copiez simplement la structure, vous écrasez le pointeur, et non ce vers quoi il pointe. Ce que vous voulez probablement faire à la place de votre memcpy est ceci :

size_t bytes = strlen(p1.name)+1;
p2.name = realloc(p2.name, bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

Ici, bytes est le nombre de caractères du nom plus le nul-terminateur, et l'appel à la fonction realloc modifie la taille de p2.name pour l'adapter. Maintenant, avec la garantie qu'il y a assez de spoace, vous pouvez memcpy le premier nom dans le second.

Utiliser realloc ici est probablement inefficace, car cela préserve le contenu original de p2.name, dont nous n'avons pas besoin. Une alternative serait de libérer d'abord l'ancienne chaîne, avant d'allouer de l'espace pour la nouvelle :

size_t bytes = strlen(p1.name)+1;
free(p2.name);
p2.name = malloc(bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

Sachez que malloc et realloc peuvent échouer et retourneront NULL si votre programme manque de mémoire, c'est donc une bonne pratique de toujours vérifier cela.

1voto

P__J__ Points 12922

Vous devez copier les zones de mémoire allouées et non les structures elles-mêmes

memcpy ( p2.name, p1.name, SIZE );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X