memcpy в C++: разбираем с примерами

C++ предоставляет много функций, которые позволяют нам оперировать памятью. Одной из таких функций является memcpy. memcpy доступна нам при подключении <cstring>. В данной статье мы разберемся, как данная функция работает, а потом рассмотрим несколько примеров, которые помогут нам закрепить изученный материал.

Как работает memcpy

Функция memcpy объявлена следующим образом:

void * memcpy (void * destination, const void * source, size_t num);

Давайте разберем ее параметры и возвращаемое значение:

  1. destination: первым параметром данная функция принимает указатель на начало участка памяти, куда будет производиться копирование;
  2. source: вторым параметром memcpy принимает указатель на участок памяти, из которого будет производиться копирование;
  3. num: последним третьим аргументом функция принимает количество байтов, которые будут скопированы из source в destination;
  4. функция возвращает указатель destination (первый аргумент memcpy).

Теперь давайте рассмотрим несколько примеров использования memcpy.

memcpy для копирования массивов чисел

Давайте начнем с простого примера копирования массива чисел int[]:

#include <iostream>
#include <cstring>
using namespace std;

int main() {
    int source[] = {1, 2, 3, 4, 5};
    int destination[5];
    memcpy(destination, source, sizeof(source));

    for (auto x: destination) {
        cout << x << " ";
    }

    return 0;
}

Оператор sizeof возвращает количество байт, которые переменная занимает в памяти.

Вывод:

1 2 3 4 5

memcpy для копирования строк

В данном примере мы скопируем одну C строку в другую. Для этого мы объявим две переменные типа char[] одинакового размера:

char source[] = "memcpy в C++";
char destination[14];
memcpy(destination, source, strlen(source) + 1);

cout << destination << endl;

Мы копируем strlen(source) + 1 байт, поскольку функция strlen не учитывает символ окончания строки \0.

Вывод:

memcpy в C++

Наша программа скопировала 14 байт из строки source в строку destination. Для разнообразия мы воспользовались функцией strlen вместо sizeof. Однако sizeof также справился бы с этой задачей.

source занимает 14 байт вместо 13 (12 символов + \0). Это связано с тем, что русские символы требуют 2 байта вместо одного.

Использование разных типов с memcpy

Стоит отметить, что memcpy никак не учитывает тип данных, на которые указывают аргументы source и destination. memcpy работает на уровне байт, поэтому мы можем производить копирование из одного типа в другой.

Чтобы продемонстрировать данную особенность, давайте скопируем массив чисел в строку при помощи memcpy:

// Строка "memcpy в C++\0" в int
int numbers[] = {1668113773, -803178128, 725819570, 43};
char str[16];

memcpy(str, numbers, sizeof(numbers));

cout << str << endl;

Мы объявляем массив str на 16 элементов, поскольку один int занимает 4 байта, в то время как char занимает только 1 байт.

Вывод программы:

memcpy в C++

Что будет выведено на экран?

double value = 3.141592653589793;
long long int copiedValue;

memcpy(&copiedValue, &value, sizeof(value));

cout << copiedValue << endl;
4614256656552045848
3.141592653589793
0000000000000000
-3.141592653589793

Пример программы

Напоследок, давайте рассмотрим пример программы, которая использует memcpy для копирования не просто массивов, а структур:

#include <iostream>
#include <cstring>

using namespace std;

struct Person {
    int age;
    double height;
    char name[50];
};

void displayPerson(const Person& p) {
    cout << "Имя: " << p.name << ", Возраст: " << p.age << ", Рост: " << p.height << " м." << endl;
}

int main() {
    Person person = {30, 1.75, "Вася Пупкин"};

    cout << "Начальные данные:" << endl;
    displayPerson(person);

    Person personCopy;
    memcpy(&personCopy, &person, sizeof(Person));

    cout << "\nСкопированные данные:" << endl;
    displayPerson(personCopy);

    // здесь мы заменяем только часть структуры Person
    int ageOnly[1] = {99};
    memcpy(&person, ageOnly, sizeof(ageOnly));

    cout << "\nМодифицированные данные:" << endl;
    displayPerson(person);

    return 0;
}

Вывод программы:

Начальные данные:
Имя: Вася Пупкин, Возраст: 30, Рост: 1.75 м.

Скопированные данные:
Имя: Вася Пупкин, Возраст: 30, Рост: 1.75 м.

Модифицированные данные:
Имя: Вася Пупкин, Возраст: 99, Рост: 1.75 м.

В данном примере мы продемонстрировали использование memcpy с C++ структурами. Мы также смогли обновить только возраст Васи не затрагивая других полей.

Упражнения

  1. Копирование массива символов:
    Напишите программу на C++, которая создает массив символов, содержащий несколько слов. Создайте второй пустой массив того же размера. Используйте функцию memcpy для копирования содержимого первого массива во второй и выведите оба массива на экран.

  2. Объединение двух массивов:
    Создайте два массива целых чисел. Создайте третий массив, который может содержать элементы обоих массивов вместе. Используйте memcpy, чтобы скопировать содержимое обоих массивов в третий. Выведите результат на экран.

  3. Манипуляции со struct:
    Определите структуру Student, которая содержит имя (строка) и возраст (целое число). Создайте экземпляр этой структуры, затем создайте пустую структуру того же типа. Используйте memcpy для копирования данных из первой структуры во вторую, затем выведите содержимое обеих структур на экран.

Обсуждение