Глубокое копирование
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 15 из 61.
Когда вы присваиваете одну структуру другой в C, вы получаете поверхностную копию: все поля копируются побайтно. Это отлично работает для простых значений, таких как целые числа, но создаёт проблему с указателями: в итоге обе структуры указывают на одну и ту же область памяти.
typedef struct {
char *name;
int age;
} Person;
Person alice = {"Alice", 30};
Person copy = alice; // Поверхностная копия!
// И alice.name, и copy.name указывают на ОДНУ И ТУ ЖЕ строку
Если ты освободишь один, другой станет недействительным. Если ты изменишь строку через один из них, оба увидят это изменение. Обычно это не то, что тебе нужно.
Глубокая копия выделяет новую память для членов-указателей и копирует данные actual:
Person *clone_person(const Person *original) {
Person *copy = malloc(sizeof(Person));
copy->name = malloc(strlen(original->name) + 1);
strcpy(copy->name, original->name);
copy->age = original->age;
return copy;
}
Теперь каждый объект владеет собственной строкой. Вы можете изменить или освободить одну из них, не затрагивая другую. Шаблон прост: для каждого указателя выделите fresh память и скопируйте содержимое, а не только адрес.
Задание
ЛегкоДавайте создадим модуль Student, демонстрирующий шаблон глубокого копирования. Вы создадите функцию клонирования, которая создает полностью независимую копию объекта студента: изменение или освобождение исходного объекта не повлияет на клон.
Вы создадите три файла:
student.h: Declare структуруStudentс двумя членами:char *name(строка, выделенная dynamically) иint grade. Declare три функции:create_student: конструктор, принимающий имя и оценку и возвращающий указатель на новый Studentclone_student: принимаетconst Student *и возвращает указатель на новую independent копиюfree_student: деструктор, который корректно освобождает всю выделенную память
STUDENT_H.student.c: Implement все три функции. Ваша функцияclone_studentявляется ключевой. Она должна выделить fresh память и для структуры, и для строки имени, а затем скопировать actual данные строки (а не только адрес указателя). Это гарантирует, что клон полностью владеет собственной памятью, отделенной от исходного объекта.main.c: Создайте студента, клонируйте его, выведите information обоих студентов, а затем корректно очистите оба объекта.
Вы получите два входных значения: имя студента (строка) и оценку (целое число).
В основном файле создайте студента с предоставленными значениями, затем создайте clone этого студента. Выведите information исходного объекта и клона, чтобы проверить, что они содержат одинаковые данные. Наконец, освободите обоих студентов и выведите подтверждение.
Выведите результат в следующем формате:
Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freedНапример, для входных данных Alice и 95 результат будет следующим:
Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freedШаблон глубокого копирования гарантирует, что каждый объект действительно independent: у клона есть собственная выделенная строка, а не общий указатель на память исходного объекта.
Попробуйте сами
#include <stdio.h>
#include <stdlib.h>
#include "student.h"
int main() {
char name[100];
int grade;
// Считать ввод
scanf("%s", name);
scanf("%d", &grade);
// TODO: Создать студента с предоставленными именем и оценкой
// TODO: Создать клон студента
// TODO: Print the original student's information
// Формат: "Original: {name}, Grade: {grade}"
// TODO: Вывести информацию о клоне
// Формат: "Clone: {name}, Grade: {grade}"
// TODO: Освободить обоих студентов
// Вывести подтверждение
printf("Both freed\n");
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C