De functie memcpy uit de standaardbibliotheek (string.h) is bedoeld voor bytegewijze kopie van een geheugengebied van de ene locatie naar de andere. Dit is een universeel hulpmiddel voor het kopiëren van arrays, structs en andere datablokken, wanneer prestaties belangrijk zijn en typeconversies niet nodig zijn.
Achtergrond:
memcpy verscheen met de eerste implementatie van de standaardbibliotheek, toen de behoefte aan de verwerking van 'ruwe' geheugengebieden ontstond, bijvoorbeeld voor het werken met bestanden, netwerkpakketten en serialisatie van gegevens. Vergelijkbare functies zijn aanwezig in bijna alle low-level talen.
Probleem:
memcpy opereert alleen op bytes, het houdt geen rekening met datatypes, alignment en overlappende geheugengebieden. Fouten bij het opgeven van de grootte of onjuiste gebieden kunnen leiden tot geheugenbeschadiging of onverwachte resultaten. Bovendien veroorzaakt het gebruik van memcpy voor overlappende gebieden onbepaald gedrag.
Oplossing:
Gebruik memcpy alleen als je zeker weet:
memmove voor overlappende gebieden.Voorbeeldcode:
#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // kopieert de struct byte voor byte
Belangrijke kenmerken:
Kan memcpy worden gebruikt voor het kopiëren van strings (char)?*
Ja, maar alleen als de lengte precies bekend is. Als de string null-terminated is, worden vaak strcpy of strncpy gebruikt. Als de grootte verwisseld wordt, kan dit leiden tot out-of-bounds geheugen of het verliezen van de terminaal nul.
char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // Er worden 3 letters + '\0' gekopieerd
Wat gebeurt er bij het kopiëren van structs met niet-standaard alignment of pointers via memcpy?
memcpy houdt geen rekening met semantiek of interne pointers. Als een struct wordt opgeslagen met dynamische velden (bijvoorbeeld char *buf;), wordt alleen het adres gekopieerd, niet de inhoud daarvan. Dit leidt tot wat men noemt 'shallow copy'.
typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // Alleen de pointer, niet de inhoud
Wat gebeurt er als src en dest in memcpy overlappen?
Het gedrag is niet gedefinieerd door de standaard, dit kan leiden tot dataverlies. Voor overweldigend kopiëren gebruik memmove:
memmove(dest, src, size); // garandeert correcte kopie
Arrays overlappen: memcpy wordt gebruikt om een deel van de array naar rechts te verschuiven, src en dest overlappen gedeeltelijk.
Voordelen:
Nadelen:
Gebruik memmove voor het verwerken van overlappende gebieden, de hoeveelheid gegevens is precies berekend als het aantal bytes in de oorspronkelijke structuur.
Voordelen:
Nadelen: