deep copy & sallow copy....

익명 사용자의 이미지

안녕하세요
c 에는 deep copy 와 sallow copy 란게 있다고 알고 있습니다.

sallow copy 는 메모리 번지만을 복사해 보는 것이기 때문에 이렇게 프로그램을
짜면 문제가 생긴다고 알고 있습니다.
그런데 제가 개념이 잘 서질 않아서 간단한 예제 프로그램을 만들어서 테스트 할려고
하는데도 잘 되지 않는군요.

누구 deep copy 와 sallow copy 의 개념에 대해서 설명 주실분 계십니까?

내가 짠 소스
1 #include
2
3 void main(void){
4 char *a;
5 char *b;
6
// a 에 메모리 할당
7 a = (char *)malloc(sizeof(char) * 10);
8
9 a = "aaa";
10
// b 를 a 에 대입하면 데이타가 복사되는 것이 아니라 주소값 복사(?)
11 b = a;
12
// 그런데 출력해 보면 두개의 주소값이 같게 나와야 되지 않나요?
// 다르게 나오는 군요 ㅠㅠ
13 printf("a = %s\n", a);
14 printf("&a = %d\n", &a);
15
16 printf("b = %s\n", b);
17 printf("&b = %d\n", &b);
18
// 제 생각에는 a 에 새로운 값을 대입하면 b 는 할당된 공간이 없고
// a 의 주소만 가지고 있기 때문에 b 의 값도 변하리라 생각했건만...
19 a = "bbb";
20
// b 의 값은 변하지 않는군요, 주소도 마찬가지고요..
21 printf("b = %s\n", b);
22 printf("&b = %d\n", &b);
23 }

익명 사용자의 이미지

b의 주소는 %d 가 아니고 %p로 변환 시켜야 됩니다.
printf("&b = %d\n", &b); 를
printf("&b = %p\n", b); 로 바꿔서 해보세요.
같은 주소로 나올겁니다.

리눅스 wrote..
안녕하세요
c 에는 deep copy 와 sallow copy 란게 있다고 알고 있습니다.

sallow copy 는 메모리 번지만을 복사해 보는 것이기 때문에 이렇게 프 로그램을
짜면 문제가 생긴다고 알고 있습니다.

문제가 생길 여지는 많이 있지만 꼭 그렇지만은 않습니다.
오히려 효율적이기도 하죠.
프로그래머의 선택 사항이라고 할 수 있습니다.

그런데 제가 개념이 잘 서질 않아서 간단한 예제 프로그램을 만들어서 테스트 할려고
하는데도 잘 되지 않는군요.

누구 deep copy 와 sallow copy 의 개념에 대해서 설명 주실분 계십니 까?
deep copy와 sallow copy의 차이는
call by value 와 call by reference 의 차이라고 생각 하시면 되겠죠.

아래의 소스를 deep copy로 한다면
#include
#include

a = (char *)malloc(sizeof(char) * 10);
b = (char *)malloc(sizeof(char) * 10);
a = strcpy(a, "aaa");
memcpy(b, a, strlen(a));

printf("&a %p\n",a);
printf("&b %p\n",b);

이렇게 하면 a와 b의 주소가 다르게 나올겁니다.
a와 b는 서로 다른 주소에 있는 "aaa"라는 문자열을 가리키고 있습니다.
결과적으로 메모리에 "aaa" 라는 문자열이 두개 있는겁니다.
deep copy죠.
sallow copy라면
a와 b는 같은 주소에 있는 "aaa"를 가리키고 있는 있습니다.
이 경우에는 메모리에는 "aaa"라는 문자열이 한개 존재합니다.

20행에 있는 b가 변하지 않는 이유는
이미 b의 값은 a가 이전에 가지고 있던 주소값을 가지고 있기 때문입니다.
a = "bbb";
라면 a 가 가지는 값은 "bbb"의 주소, 즉 새로운 값입니다.
b와는 관계 없는 일이죠.

도움이 되셨는지 모르겠네요.
그림을 그려서 설명하면 좀 쉬울텐데..

내가 짠 소스
1 #include<stdio.h>
2
3 void main(void){
4 char *a;
5 char *b;
6
// a 에 메모리 할당
7 a = (char *)malloc(sizeof(char) * 10);
8
9 a = "aaa";
10
// b 를 a 에 대입하면 데이타가 복사되는 것이 아니라 주소 값 복사(?)
11 b = a;
12
// 그런데 출력해 보면 두개의 주소값이 같게 나와야 되지 않 나요?
// 다르게 나오는 군요 ㅠㅠ
13 printf("a = %s\n", a);
14 printf("&a = %d\n", &a);
15
16 printf("b = %s\n", b);
17 printf("&b = %d\n", &b);
18
// 제 생각에는 a 에 새로운 값을 대입하면 b 는 할당된 공 간이 없고
// a 의 주소만 가지고 있기 때문에 b 의 값도 변하리라 생 각했건만...
19 a = "bbb";
20
// b 의 값은 변하지 않는군요, 주소도 마찬가지고요..
21 printf("b = %s\n", b);
22 printf("&b = %d\n", &b);
23 }

익명 사용자의 이미지

답변 감사합니다.

sallow copy 일 경우에 님께서 , '문제가 될 소지는 많지만..
효율적이기도 하다....' 말씀하셨는데.. 이것은

b = a; 이럴 경우 b가 a 의 주소값을 가지고 있는데 만약 a 의 메모리
영역을 다른 값을로 덮어썼을 경우, b 의 값도 덩달아서 변하게 되는
것이 문제가 될 소지이고,

효율적인 면도 있다는 것은 memcopy 를 하는 것보다 속도면에서
메모리 주소만 복사하는 것이 빠르기 때문인가요?

익명 사용자의 이미지

우선 님께서 이해하지 못하고 계신 상황을 설명해봅시다.

1.
소스코드에서의 "aaa"와 같은 문자열은 컴파일러에게 무슨 의미 일까요?
컴파일러는 aaa라는 문자열을 발견하면, 메모리상의 특정 영역에 이를
저장합니다. 그리고 그 저장한 곳의 첫번째 주소를 "aaa"대신에 사용하죠.
이것이 바로 님의 프로그램에서 a="aaa"를 가능하게하는 것입니다.

따라서 라인 9에서 님은 a라는 문자 포인터에 "aaa"라는 문자열의 첫번째
주소를 대입시킨 것이되는 것이지, 라인 7에서 자유메모리 공간상에
예약한 곳에 문자열 "aaa"를 대입한게 아니라는 겁니다. 바꾸어
말하면 님은 라인 7에서 예약한 주소를 사용하지 않고 내버린 것입니다.
이런 코딩이 메모리 유출의 시작이죠. --;
님의 원래 의도되로 하려면 프로그램의 첫머리에 #include를
하고, 라인 9에 a="aaa";가 아니라 strcpy(a,"aaa");를 사용했어야 합니
다.

프로그램의 마지막에 free(a);를 첨가해서 예약한 메모리를 되돌려주는
것도 잊지 말아야 겠군요.

2.
어찌되었든 님의 방식대로 프로그램이 진행되었다고 봅시다.
이제 a라는 포인터 변수는 메모리상의 어딘가에 저장된 "aaa"문자열의
첫번째 주소를 가지고 있습니다. 그리고 님께선 b=a;라고 하셨습니다.
이는 님이 말씀하신대로 얕은(shallow)복사입니다. b라는 문자열
포인터에 a라는 문자열 포인터의 값을 복사했기 때문이죠. 따라서 현재
a와 b는 모두 메모리상의 동일한 공간을 나타내고 있습니다.

그런데!!! 왜 님의 생각과는 달리 printf문은 다른 주소를 보여줄까요?
그것은 님께서 printf문을 사용할 때 또다른 실수를 했기 때문이죠.
char *a;를 프로그램의 첫머리에서 선언한거 기억하시죠? 그렇다면
a라는 변수에는 무엇이 저장되어있을까요? 당연히 a가 가리키고 있는
대상의 메모리 번지입니다. 헌데, &a는 그럼 무엇일까요? &a는 a라는
포인터 변수 자기자신의 메모리 번지입니다. 따라서 님께서 사용하신
> 14 printf("&a = %d\n", &a);
구문은 a가 가리키고 있는 문자열의 번지수를 화면에 표시한 것이 아니라
a라는 포인터 변수 자신의 주소를 화면에 표시한 것입니다. 그러니 그다음

> 17 printf("&b = %d\n", &b);
라고 하면 다른 주소가 나올 수 밖에요. 라인 17은 b라는 포인터 변수 자
신의
주소를 화면에 표시한 것이니 당연히!!! a라는 포인터 변수의 주소와는
다른 값이 찍히겠죠. 그럼 님의 의도대로 프로그램을 고치면 이렇습니다.
13 printf("*a = %s\n", a);
14 printf("a = %d\n", a);
15
16 printf("*b = %s\n", b);
17 printf("b = %d\n", &b);
이렇게 하면 현재 동일한 주소를 가리키고 있는 포인터변수 a와 b의
"내용물"을 라인 14와 라인 17이 출력해줄 수 있을 것이고, 님의 예상과
동일한 결과가 나올 것입니다.

3.
여기까지 이해했다면 당연히 라인 21과 22가 틀렸음을 짐작할 수 있겠죠?
그럼.. 이만

> 1 #include
> 2
> 3 void main(void){
> 4 char *a;
> 5 char *b;
> 6
> // a 에 메모리 할당
> 7 a = (char *)malloc(sizeof(char) * 10);
> 8
> 9 a = "aaa";
> 10
> // b 를 a 에 대입하면 데이타가 복사되는 것이 아니라 주소
값 복사(?)
> 11 b = a;
> 12
> // 그런데 출력해 보면 두개의 주소값이 같게 나와야 되지 않
나요?
> // 다르게 나오는 군요 ㅠㅠ
> 13 printf("a = %s\n", a);
> 14 printf("&a = %d\n", &a);
> 15
> 16 printf("b = %s\n", b);
> 17 printf("&b = %d\n", &b);
> 18
> // 제 생각에는 a 에 새로운 값을 대입하면 b 는 할당된 공
간이 없고
> // a 의 주소만 가지고 있기 때문에 b 의 값도 변하리라 생
각했건만...
> 19 a = "bbb";
> 20
> // b 의 값은 변하지 않는군요, 주소도 마찬가지고요..
> 21 printf("b = %s\n", b);
> 22 printf("&b = %d\n", &b);
> 23 }

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.