Est-il correct d'utiliser memcpy() pour copier une structure qui contient un pointeur?
Je pensais à ce sujet l'autre jour, et je suis curieux de savoir si c'est une mauvaise idée...
Permet de dire qu'il n'y est une structure qui contient un pointeur vers un tableau de chaînes.
Serait le memcpy() copie le nom de pointeur sur le tableau dans l'exemple ci-dessous?
Edit: Le mst est inaccessible dans cet exemple.
struct charMap
{
unsigned char * name;
unsigned char id;
};
typedef struct charMap CharMapT;
class ABC
{
public:
ABC(){}
void Function();
CharMapT* structList;
}
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
structList = new CharMapT[sizeof(list)];
memcpy(structList, &list, sizeof(list));
}
Pour le code c++, pourrais-je vous suggérer std::copy au lieu de
Et
Ceci est appelé une copie superficielle.
Ne pouvez pas utiliser std lib. Je suis dans le monde embarqué.
N'ayant pas accès à un conforme compilateur c++ (ou avoir d'autres raisons qui vous empêchent de rédaction de la norme c++) est quelque chose que vous pourriez vouloir mentionner dans votre question.
memcpy
et, éventuellement, std::vector au lieu de c style des tableaux?Et
std::string
au lieu de chaînes de style c 🙂Ceci est appelé une copie superficielle.
Ne pouvez pas utiliser std lib. Je suis dans le monde embarqué.
N'ayant pas accès à un conforme compilateur c++ (ou avoir d'autres raisons qui vous empêchent de rédaction de la norme c++) est quelque chose que vous pourriez vouloir mentionner dans votre question.
OriginalL'auteur RLefevre | 2012-11-27
Vous devez vous connecter pour publier un commentaire.
Il y a plusieurs erreurs dans le code présenté, je vais parler en premier, suivi par mon stock-diatribe de pointeurs vs tableaux.
Il déclare un type de structure qui comprend un pointeur vers unsigned int comme le premier membre de (nom) et un int comme le second membre (id). Sur un système 32 bits par défaut en octets de l'emballage ce sera 8 octets large (pointeur de 32 bits = 4 octets, 32-bit signé int=4 octets). Si c'est une machine 64 bits, les pointeurs sera de 8 octets de large, l'int toujours susceptibles de 32 bits, ce qui fait de la taille de la structure 12 octets.
Discutable Code
Il alloue un tableau dynamique de CharMapT des structures. Combien? Plus que vous ne le pensez. Le
sizeof(list)
sera de retour le byte-comte de lalist[]
tableau. Depuis un CharMapT structure est de 8 octets de large (voir ci-dessus), il faut en 3 * 8, ou 24 CharMapT éléments (36 points, si à l'aide de pointeurs 64-bit).Nous avons ensuite
memcpy()
24 octets (ou 36 octets) à partir delist
(le&
dans&list
est inutile) à la mémoire nouvellement allouée. cela permettra de copier plus de 3 CharMapT structures, laissant les autres 21, nous avons alloué intacte (au-delà de leur valeur initiale par défaut de construction).Note: vous êtes l'initialisation d'un
const char *
à un champ déclaré queunsigned int *
, donc, si cette même compilé le type de données fondamental serait différent. En supposant que vous avez fixé votre structure et de modifier le type de pointeur pourconst char *
, les adresses de la statique des constantes de chaîne (les adresses de la rubrique "NOM" constantes) quelque part dans votre const segment de données sera affectée à la variable pointeur des éléments dans structList[0].nom, structList[2].nom, et structList[3].nom respectivement.Ce ne sera PAS copier les données de relever à. il ne copie que le pointeur valeurs. Si vous voulez des copies de données, alors vous devez raw de les affecter (malloc, de nouveau, peu importe).
Mieux encore, utiliser une
std::vector<CharMapT>
, utilisezstd::string
pourCharMapT::name
, et l'utilisationstd::copy()
à reproduire la source (ou même directement de cession).J'espère que explique ce que vous cherchez.
Pointeur vs Tableau Diatribe
Jamais confondre un pointeur d'un tableau. Un pointeur est une variable que détient une adresse. Tout comme un
int
variable tenir un entier de valeur, ou unchar
variable contient un type de caractère, la valeur à un pointeur est une adresseUn tableau est différent. Il est également une variable (évidemment), mais il ne peut pas être une l-value, et près de tous les endroits où elle est généralement utilisée une conversion se produit. Sur le plan conceptuel que les résultats de la conversion dans un temporaire pointeur qui pointe vers le type de données de la matrice, et contient l'adresse du premier élément. Il ya des moments où cette notion ne pas se produisent (comme l'application de l'adresse de l'opérateur).
ou ceci:
mais pas cette:
Excellent post. Vous êtes le seul à choisir également sur le fait que le [nouveau] de façon spectaculaire overallocates.
+1, vous avez passé plus de temps sur ce que j'ai fait.
un témoignage de ma vie ennuyeuse, je pense =P
Je vous remercie. Cela a été très utile.
OriginalL'auteur WhozCraig
Il ne sera pas la copie de vos données pointées par
name
. Il copie le pointeur et vous aurez 2 pointeurs à la même place dans les 2 objets (pour chaque paire d'objets dans les 2 tableaux).Pourquoi non signé? Pourquoi muable? Il devrait être un
const char*
.Donc, memcpy est de copier l'adresse de pointeur, pas le " nom " de données? C'est probablement du mal parce que la liste[] est sur le tas de données serait perdu, non?
est alloué automatique de la durée de stockage, c'est à dire, le pile, pas le tas. Et oui, vous avez maintenant balançant des pointeurs qui sont valable une fois que la fonction retourne. Vous aurez besoin de copier le tableau lui-même si vous êtes coincé à l'aide de C (ce n'est vraiment pas en C++, en plus C avec des classes, en supposant que les devoirs).
Merci Ed (sa été une longue journée... oui, la pile). Je le prends donc le *nom des pointeurs dans le *structList tableau sont toutes bancales après Function() est terminée?
OriginalL'auteur SomeWittyUsername
Tous vous avez vraiment besoin de savoir ici, c'est que
memcpy
vous donnera un bit à bit copie de l'original. Donc, ce que vous aurez est de deux pointeurs avec la même valeur (c'est à dire, une adresse) qui se réfèrent aux mêmes données.Sur une note de côté, vous avez déclaré
name
comme un pointeur versint
, ce qui est évidemment faux. Il devrait être unconst char*
. Aussi, comme c'est le C++ et pas en C, vous êtes mieux servi par quelque chose commestd::copy
qui ne cassera pas votre code subtilement sicharMap
un jour devient un type complexe. Sur la même note, préférezstd::string
au lieu deconst char*
dans la plupart des situations.OriginalL'auteur Ed S.
Votre utilisation de
sizeof()
est mal lors de l'appel denew
. Vous êtes l'allocation d'un tableau deCharMapT
éléments. Vous devez spécifier le nombre d'éléments, mais vous spécifiez un nombre d'octets à la place. Si vous devez corriger l'erreur:Avec qui fixe, le résultat de la
memcpy()
sera questructList
contient une copie exacte des données brutes quilist[]
contient. Cela signifie que lestructList[N].name
pointeurs contiennent les mêmes valeurs que lelist[N].name
pointeurs, et donc, ils vont tous être orientés vers le même mémoire physique pour la chaîne de valeurs.Si vous voulez faire une copie en profondeur de la chaîne de valeurs, vous devez allouer séparément, par exemple:
OriginalL'auteur Remy Lebeau
Je voudrais ajouter à @EdS.'s réponse:
Votre code est juste beaucoup plus c++ de style c code c++ si vous le faites comme ceci:
Pourquoi ne pas utiliser
std::vector
pour faire un tableau? Vous pouvez le faire comme ceci:Il est plus sûr, aussi, éviter d'utiliser des pointeurs diminue le risque de fuites de mémoire ou de bugs dus à une mauvaise utilisation de la
sizeof
opérateur.Je suppose que vous ne voulez pas vraiment un structList, qui a autant d'éléments que l' la taille de la mémoire de votre liste. (Si la liste est le double de ce qui pourrait être plusieurs fois plus que le nombre d'éléments dans votre liste.)
Aussi,
memcpy
n'est pas vraiment nécessaire, si la liste est également un vecteur (qui est une fonction c vraiment). Vous venez de faire une simple affecter le fonctionnement:Cela va copier les éléments comme memcpy.
OriginalL'auteur Barnabas Szabolcs