Функция memcpy из стандартной библиотеки (string.h) предназначена для побайтного копирования области памяти из одного места в другое. Это универсальный инструмент для копирования массивов, структур и других блоков данных, когда важна производительность и не нужны преобразования типов.
История вопроса:
memcpy появился вместе с первой реализацией стандартной библиотеки, когда возникла необходимость в обработке «сырых» блоков памяти, например, для работы с файлами, сетевыми пакетами, сериализацией данных. Сходные функции присутствуют почти во всех низкоуровневых языках.
Проблема:
memcpy оперирует только байтами, она не заботится о типах данных, выравнивании, перекрытии областей памяти. Ошибки указания размера или некорректных областей приводят к повреждению памяти или неожиданным результатам. Кроме того, применение memcpy для перекрывающихся областей вызывает неопределённое поведение.
Решение:
Используйте memcpy, только если уверены:
memmove.Пример кода:
#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // копируем структуру побайтно
Ключевые особенности:
Можно ли использовать memcpy для копирования строк (char)?*
Можно, только если точно известна длина. Если строка — null-terminated, часто используют strcpy или strncpy. Если перепутать размер — возможен выход за пределы памяти или потеря завершающего нуля.
char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // Копируются 3 буквы + '\0'
Что произойдет при копировании структур с нестандартным выравниванием или указателями через memcpy?
memcpy не учитывает ни семантику, ни внутренние указатели. Если структура хранит динамические поля (например, char *buf;), копируется только сам адрес, а не содержимое по нему. Это приводит к так называемому «поверхностному» копированию.
typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // Только поле-указатель, не содержимое
Что будет, если src и dest в memcpy перекрываются?
Поведение не определено стандартом, может возникнуть потеря данных. Для копирования с перекрытием используйте memmove:
memmove(dest, src, size); // гарантирует корректное копирование
Массивы перекрываются: применяется memcpy для сдвига части массива вправо, src и dest частично совпадают.
Плюсы:
Минусы:
Используется memmove для обработки перекрывающихся областей, объём данных чётко вычислен как количество байт в исходной структуре.
Плюсы:
Минусы: