web-dev-qa-db-fra.com

Copier une structure dans une autre

Je sais que je peux copier la structure membre par membre, à la place puis-je faire une memcpy sur des structures?

Est-il conseillé de le faire?

Dans ma structure, j'ai également une chaîne en tant que membre que je dois copier dans une autre structure ayant le même membre. Comment je fais ça?

45
asir

La copie par affectation simple est préférable, car elle est plus courte, plus facile à lire et a un niveau d'abstraction plus élevé. Au lieu de dire (au lecteur humain du code) "copiez ces bits d’ici là" et de demander au lecteur de réfléchir à l’argument de taille pour la copie, vous ne faites qu’une simple assignation ("copier cette valeur depuis ici à ici "). Il ne peut y avoir aucune hésitation quant à savoir si la taille est correcte ou non.

De plus, si la structure est fortement matelassée, l’affectation peut amener le compilateur à émettre quelque chose de plus efficace, car il n’a pas besoin de copier le bourrage (et il sait où il se trouve), mais mempcy() ne le fait pas, il copie toujours exactement le bourrage. nombre d'octets que vous dites de copier.

Si votre chaîne est un tableau réel, c’est-à-dire:

struct {
  char string[32];
  size_t len;
} a, b;

strcpy(a.string, "hello");
a.len = strlen(a.string);

Ensuite, vous pouvez toujours utiliser une affectation simple:

b = a;

Pour obtenir une copie complète. Pour les données de longueur variable ainsi modélisées, ce n’est pas le moyen le plus efficace de faire la copie car tout le tableau sera toujours copié.

Attention cependant, la copie de structures contenant des pointeurs dans de la mémoire allouée peut être un peu dangereuse, car, ce faisant, vous utilisez aliasing le pointeur, ce qui rend généralement ambigu le propriétaire du pointeur après la copie.

Pour ces situations, une "copie en profondeur" est vraiment le seul choix, et cela doit aller dans une fonction.

59
unwind

Depuis C90, vous pouvez simplement utiliser:

dest_struct = source_struct;

tant que la chaîne est mémorisée dans un tableau:

struct xxx {
    char theString[100];
};

Sinon, si c'est un pointeur, vous devrez le copier à la main.

struct xxx {
    char* theString;
};

dest_struct = source_struct;
dest_struct.theString = malloc(strlen(source_struct.theString) + 1);
strcpy(dest_struct.theString, source_struct.theString);
37
Simone

Si les structures sont de types compatibles, oui, vous pouvez, avec quelque chose comme:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));

La seule chose dont vous devez être conscient est qu’il s’agit d’une copie peu profonde. En d'autres termes, si vous avez un char * pointant vers une chaîne spécifique, les structures both pointeront vers la même chaîne.

Et changer le contenu de l'un de ces champs de chaîne (les données sur lesquelles le char * pointe, et non le char * lui-même) modifiera également l'autre.

Si vous voulez une copie facile sans avoir à faire manuellement chaque champ mais avec le bonus supplémentaire de copies de chaînes non superficielles, utilisez strdup:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));
dest_struct->strptr = strdup (source_struct->strptr);

Cela copiera l'intégralité du contenu de la structure, puis procédera à une copie en profondeur de la chaîne, ce qui donnera une chaîne distincte à chaque structure.

Et, si votre implémentation C ne possède pas de strdup (elle ne fait pas partie de la norme ISO), obtenez-en une à partir de maintenant .

14
paxdiablo

Vous pouvez memcpy struct, ou vous pouvez simplement les assigner comme n'importe quelle autre valeur.

struct {int a, b;} c, d;
c.a = c.b = 10;
d = c;
4
Conrad Meyer

Vous pouvez utiliser la solution suivante pour atteindre votre objectif:

struct student 
{
    char name[20];
    char country[20];
};
void main()
{
    struct student S={"Wolverine","America"};
    struct student X;
    X=S;
    printf("%s%s",X.name,X.country);
}
0
Anvesh

En C, la mémoire n’est bêtement risquée. Tant que les trois paramètres sont exacts, aucun des membres de la structure ne sont des pointeurs (ou vous avez explicitement l'intention de faire une copie superficielle) et il n'y a pas de grandes lacunes dans l'alignement de la structure que memcpy va perdre du temps à parcourir. (ou la performance ne compte jamais), alors bien sûr, mémoire. Vous ne gagnez rien sauf un code plus difficile à lire, fragile aux modifications futures et devant être vérifié à la main dans les revues de code (car le compilateur ne le peut pas), mais bon, bien sûr, pourquoi pas.

En C++, nous avançons vers le risible ridicule. Vous pouvez avoir des membres de types qui ne sont pas mémorisables en toute sécurité, tels que std :: string, qui transformeront votre structure réceptrice en une arme dangereuse, corrompant de manière aléatoire la mémoire chaque fois qu'elle est utilisée. Vous pouvez avoir des surprises impliquant des fonctions virtuelles lors de l’émulation de copies découpées. L’optimiseur, qui peut faire des choses merveilleuses pour vous car il a la garantie de connaître parfaitement le type lorsqu’il compile =, ne peut rien faire pour votre appel mémoire.

En C++, il existe une règle de base: si vous voyez memcpy ou memset, quelque chose ne va pas. Il existe de rares cas où ce n'est pas vrai, mais ils n'impliquent pas de struct. Vous utilisez memcpy quand, et seulement quand, vous avez raison de aveuglément copier octets

Par contre, l’affectation est simple à lire, vérifie l’exactitude au moment de la compilation, puis déplace intelligemment values ​​ au moment de l’exécution. Il n'y a pas d'inconvénient.

0
user15001