Menu
Coddy logo textTech

깊은 복사

Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 15번째.

C 언어에서 하나의 구조체(struct)를 다른 구조체에 대입할 때, 얕은 복사(shallow copy)가 수행됩니다. 즉, 모든 필드가 바이트 단위로 복사됩니다. 이는 정수와 같은 단순한 값에는 잘 작동하지만, 포인터의 경우에는 문제가 발생합니다. 두 구조체가 결국 동일한 메모리를 가리키게 되기 때문입니다.

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // 얕은 복사!
// alice.name과 copy.name 모두 동일한 문자열을 가리킵니다

하나를 해제하면 다른 하나는 유효하지 않게 됩니다. 하나를 통해 문자열을 수정하면 두 곳 모두에 변경 사항이 반영됩니다. 이는 대개 여러분이 원하는 결과가 아닙니다.

깊은 복사(deep copy)는 포인터 멤버를 위해 새로운 메모리를 할당하고 실제 데이터를 복사합니다:

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;
}

이제 각 객체는 고유한 문자열을 소유합니다. 다른 객체에 영향을 주지 않고 하나를 수정하거나 해제할 수 있습니다. 이 패턴은 명확합니다. 각 포인터 멤버에 대해 새로운 메모리를 할당하고, 단순히 주소만 복사하는 것이 아니라 내용을 복사하는 것입니다.

challenge icon

챌린지

쉬움

딥 카피(deep copy) 패턴을 보여주는 Student 모듈을 만들어 보겠습니다. 원본을 수정하거나 해제해도 복제본에 아무런 영향을 주지 않는, 완전히 독립적인 학생 객체 복사본을 생성하는 클로닝 함수를 만들 것입니다.

세 개의 파일을 생성하게 됩니다:

  • student.h: 두 개의 멤버를 가진 Student 구조체를 선언합니다: char *name (동적으로 할당된 문자열)과 int grade. 다음 세 가지 함수를 선언합니다:
    • create_student — 이름과 성적을 받아 새로운 Student에 대한 포인터를 반환하는 생성자
    • clone_studentconst Student *를 받아 새롭고 독립적인 복사본에 대한 포인터를 반환하는 함수
    • free_student — 할당된 모든 메모리를 적절히 해제하는 소멸자
    STUDENT_H 심볼을 사용하여 인클루드 가드(include guards)를 적용하세요.
  • student.c: 세 가지 함수를 모두 구현합니다. clone_student 함수가 핵심입니다. 이 함수는 구조체와 이름 문자열 모두를 위해 새로운 메모리를 할당한 다음, 실제 문자열 데이터(포인터 주소만이 아닌)를 복사해야 합니다. 이를 통해 복제본이 원본과 완전히 분리된 자체 메모리를 소유하도록 보장합니다.
  • main.c: 학생을 생성하고, 이를 복제하고, 두 학생의 정보를 표시한 다음, 두 객체를 모두 적절히 정리합니다.

두 개의 입력을 받게 됩니다: 학생 이름 (문자열)과 성적 (정수).

메인 파일에서 제공된 값으로 학생을 생성한 다음, 해당 학생의 복제본을 만듭니다. 원본과 복제본의 정보를 모두 출력하여 동일한 데이터를 포함하고 있는지 확인하세요. 마지막으로 두 학생을 모두 해제하고 확인 메시지를 출력합니다.

출력은 다음 형식으로 하세요:

Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freed

예를 들어, 입력값이 Alice95인 경우 출력은 다음과 같습니다:

Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freed

딥 카피 패턴은 각 객체가 진정으로 독립적임을 보장합니다. 즉, 복제본은 원본 메모리에 대한 공유 포인터가 아니라 자신만의 할당된 문자열을 가집니다.

치트 시트

C에서 하나의 구조체를 다른 구조체에 할당하면 얕은 복사(shallow copy)가 수행됩니다. 즉, 모든 필드가 바이트 단위로 복사됩니다. 포인터의 경우, 두 구조체는 결국 동일한 메모리를 가리키게 됩니다:

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // 얕은 복사!
// alice.name과 copy.name 모두 동일한 문자열을 가리킵니다.

깊은 복사(deep copy)는 포인터 멤버를 위해 새로운 메모리를 할당하고 실제 데이터를 복사합니다:

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;
}

깊은 복사 패턴: 각 포인터 멤버에 대해 새로운 메모리를 할당하고 주소만이 아닌 내용을 복사합니다. 이를 통해 각 객체는 자신의 메모리를 소유하게 되며 독립적으로 수정하거나 해제할 수 있습니다.

직접 해보기

#include <stdio.h>
#include <stdlib.h>
#include "student.h"

int main() {
    char name[100];
    int grade;
    
    // 입력 읽기
    scanf("%s", name);
    scanf("%d", &grade);
    
    // TODO: 제공된 name과 grade를 사용하여 student 생성
    
    // TODO: student의 복제본(clone) 생성
    
    // TODO: 원본 student의 정보 출력
    // 형식: "Original: {name}, Grade: {grade}"
    
    // TODO: 복제본(clone)의 정보 출력
    // 형식: "Clone: {name}, Grade: {grade}"
    
    // TODO: 두 student 모두 메모리 해제(Free)
    
    // 확인 메시지 출력
    printf("Both freed\n");
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨