얕은복사(Shallow Copy) & 깊은복사(Deep Copy)

구조체 내부에 포인터가 포함되어 있을 경우 구조체 변수에 대한 대입을 알아보기 전에 먼저 **얕은복사(Shallow copy)와 깊은 복사(Deep copy)**에 대한 개념을 알아야 한다. 얕은 복사란 대입 연산자를 통해 사본을 만드는 것이다 이는 구조체의 멤버들이 정수나 실수 따위의 단순 타입일 경우에 가능하다. 깊은 복사란 포인터 변수가 가지는 주소값, 구조체 멤버들이 가르키는 값 즉, 구조체 멤버가 포인터 타입을 가지는 변수에 대해 같은 타입의 포인터 변수에 원본 복사하는 것이다. 포인터 타입을 멤버로 두는 구조체를 얕은 복사로 같은 타입의 구조체 변수에 대입을 한다면 각 구조체의 포인터 타입의 멤버는 같은 주소를 가르킨다. 이때 얕은 복사로서 대입에는 문제가 없지만 이 구조체 멤버의 변수를 함수로 호출할 경우 컴파일러 에러가 발생한다. 컴파일러는 주소가 같은 두 포인터 변수에 대한 모호성 즉 두 개의 포인터 주소가 동일함에 따라 원본의 의미가 없어져 메모리 문제로 인한 에러가 발생한다.

해결법

구조체 멤버가 포인터 타입을 가지더라도 복사할 구조체의 포인터 변수에 대해 크기만큼 동적할당 후 원본의 내용을 복사한다면 구조체의 포인터 타입의 멤버가 가르키는 곳의 내용까지도 복사하는 깊은 복사가 가능하다.

#include<stdio.h>
#include<string.h>
#include<malloc.h>
struct tag_Person
{
    char *pName;
    int Age;
    double Height;
};
void main()
{
    tag_Person Albert = { NULL, 80, 154.0 };
    tag_Person Kim;
 
    Albert.pName = (char *)malloc(32);
    strcpy(Albert.pName, "알버트 아인슈타인"); 
    
    Kim = Albert;
    Kim.pName = (char *)malloc(strlen(Albert.pName) + 1);
		**//Kim = Albert 즉 대입을 한 후 kim.pName에 새롭게 동적할당을 한다**.
   **** 
		strcpy(Kim.pName, Albert.pName);
    printf("이름 = %s, 나이 = %d, 키 = %.2f\n", Kim.pName, Kim.Age, Kim.Height);
 
    strcpy(Albert.pName, "아이작 뉴튼");
    printf("이름 = %s, 나이 = %d, 키 = %.2f\n", Kim.pName, Kim.Age, Kim.Height);
    free(Albert.pName);
    free(Kim.pName);
}

응용

****구조체에 자기 자신을 가르키는 포인터를 멤버로 두고 자기 자신을 가르키는 포인터 멤버에 대해 필요에 따라 동적할당을 하고 값을 넣는다면 메모리 효율과 더불어 연속적인 깊은 복사를 통한 리스트를 구현할 수 있다.