Funkcja memcpy z biblioteki standardowej (string.h) służy do kopiowania obszaru pamięci bajtowo z jednego miejsca do drugiego. Jest to uniwersalne narzędzie do kopiowania tablic, struktur i innych bloków danych, gdy ważna jest wydajność i nie są potrzebne konwersje typów.
Historia pytania:
memcpy powstał wraz z pierwszą realizacją biblioteki standardowej, kiedy pojawiła się potrzeba obsługi „surowych” bloków pamięci, na przykład do pracy z plikami, pakietami sieciowymi, serializacją danych. Podobne funkcje występują prawie we wszystkich językach niskiego poziomu.
Problem:
memcpy operuje tylko na bajtach, nie dba o typy danych, wyrównanie ani nakładanie się obszarów pamięci. Błędy w określeniu rozmiaru lub niewłaściwych obszarów prowadzą do uszkodzenia pamięci lub nieoczekiwanych wyników. Ponadto, stosowanie memcpy dla nakładających się obszarów powoduje niezdefiniowane zachowanie.
Rozwiązanie:
Używaj memcpy tylko wtedy, gdy masz pewność:
memmove.Przykład kodu:
#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // kopiujemy strukturę bajtowo
Kluczowe cechy:
Czy można używać memcpy do kopiowania napisów (char)?*
Można, tylko jeśli dokładnie znana jest długość. Jeśli napis jest zakończony null, często używa się strcpy lub strncpy. Jeśli pomylisz rozmiar — możliwe jest przekroczenie granic pamięci lub utrata zakończenia null.
char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // Kopiowane 3 litery + '\0'
Co się stanie podczas kopiowania struktur z nietypowym wyrównaniem lub wskaźnikami za pomocą memcpy?
memcpy nie uwzględnia ani semantyki, ani wewnętrznych wskaźników. Jeśli struktura przechowuje pola dynamiczne (na przykład char *buf;), kopiowany jest tylko sam adres, a nie zawartość, do której on wskazuje. Prowadzi to do tak zwanego „płytkiego” kopiowania.
typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // Tylko pole wskaźnika, nie zawartość
Co się stanie, jeśli src i dest w memcpy się nakładają?
Zachowanie nie jest zdefiniowane przez standard, może dojść do utraty danych. Aby skopiować z nakładaniem, użyj memmove:
memmove(dest, src, size); // zapewnia poprawne kopiowanie
Tablice nakładają się: stosuje się memcpy do przesuwania części tablicy w prawo, src i dest częściowo się pokrywają.
Zalety:
Wady:
Używa memmove do obsługi nakładających się obszarów, objętość danych została dokładnie obliczona jako liczba bajtów w strukturze źródłowej.
Zalety:
Wady: