ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 메모리 복사
    C언어 2020. 3. 5. 18:24

    이번 포스트에서 다룰 내용은 메모리에 담긴 값을 복사하는 방법에 대해서 다룰 것이다.

    가장 쉽게 복사하는 방법은 단순대입 연산자를 통하여 r - value 의 값을 왼쪽의 l - value 의 값으로 옮기는 방법이다.

    int main(void)
    {
    	int num = 10;
    	int cp_num = 0;
    
    	cp_num = num;
    	printf("%d", cp_num);
    
    }

     또한 l-value의 값은 항상 변수만 가능하다.  따라서 cp_num 이라는 변수에 0이라는 값을 over write 하고 num이라는 변수에 있는 10이라는 값을 새롭게 넣은 것이다. 그렇다면 이러한 인스턴스들의 집합은 어떻게 복사해야 하는가 ? 즉 배열의 경우 어떻게 복사하여야 하는가 ? 라는 의문이 생긴다. 한번 위의 경우와 같이 복사해보자

    int main(void)
    {
    	char ch[12] = { "Hello" };
    	char cp_ch[12] = { 0 };
    
    	cp_ch = ch;
    
    }

     현재 식별자 ch안에 담긴 값은 char 문자 배열인 "Hello" 라는 문자열 상수가 들어가 있다. 이때 같은 크기의 배열인 cp_ch라는 배열에 단순대입 하여 프로그램을 실행 시켰을때 이다.

    다음과 같은 애러가 발생한다. 애러의 내용을 보면 왼쪽의 피연산자가 l-value 즉 변수여야 한다는 의미이다. 바로 이 부분에서 대다수의 사람들이 실수를 하게 된다. 위에서 사용한 변수와 동일시 하여 배열을 다루기 때문이다. 이전 포스트에서 배열은 주소로 식별 된다고 하였다. 따라서 식별자가 가리키는 것은 주소라고 하였다.

    즉 cp_ch = ch; 구문은 cp_ch 라는 배열의 식별자가  l-value 자리에 기술 되었음으로 주소가 들어간 거라고 볼 수 있다. 따라서 주소는 0x0018FF1C와 같은 상수형태 이기때문에 변수가 들어가야 할 자리에 상수가 들어감에 따라 애러가 발생 한 것이다. 

    또한 r - value의 값은 배열 ch의 식별자를 기술 하였다 이는 배열 ch의 인스턴스의 값이 아닌 ch 배열의 주소에 해당 하는 값이 넘겨지게 된다. 따라서 사용자는 값을 넘길지, 주소를 넘길지 확실히 인지하고 프로그램을 작성해야 한다.

     

     

     

    Shallow copy 

    배열의 식별자가 주소를 가리킨다는 사실을 망각 한 채로 프로그램을 작성하다 보면 위와 같은 실수를 할 수 있다. 이러한 실수는 매우 빈번하게 일어나며 shallow copy 라는 명칭으로 부르고 있다.

    int main(void)
    {
    	char ch[12] = { "Hello" };
    	char *pch = NULL;
    
    	// 메모리 동적 할당
    	pch = (char *)malloc(sizeof(ch) / sizeof(char));
    
    	// 포인터 변수에 ch 주소 단순 대입
    	pch = ch;
    
    	puts(pch);
    
    	free(pch);
    
    }

    1. pch 포인터에 동적할당받은 메모리 주소를 단순대입 ( 아래 메모리 창 확인 )

    현재 동적 할당 받은 메모리는 0x 00 28 6B 50 주소의 Heap 메모리 이다.

     

    2. pch 포인터에 ch 배열의 주소를 단순대입 따라서 Over Write 발생 (동적 할당 받은 메모리의 주소 유실)

    위와 같이 pch 포인터에 단순대입이 이루어 지면서 기존에 동적 할당 받은 메모리가 덮어쓰기 된다. 따라서 ch 배열의 주소인 0x 00 18 FF 14 의 stack 메모리를 가리키게 된다.

    3. free 함수를 통해 동적 할당 받은 메모리의 주소를 반환해 주어야 하는데 이때 pch 포인터가 가리키는 메모리는 stack 메모리 영역인 ch의 주소이다 따라서 오류가 발생하게 된다. ( 하지만 pch 포인터에 ch 배열의 주소가 있기 때문에 pch 포인터에 있는 주소의 메모리로 접근 하면 Hello 문자열이 있기 때문에 출력은 Hello 가 된다 )

     

     

    Deep copy

    이제 주소의 개념과 주소가 가리키는 메모리 안에 있는 값의 개념은 충분히 구분할 수 있을 것이다. 즉 배열의 내용을 복사하고 싶다면 배열의 주소를 기술하는 것이 아니라 해당 주소가 가리키는 메모리의 값을 복사해야 할 것이다. 또한 이렇게 주소가 가리키는 메모리의 값을 복사하는 것을 Deep copy 라고 칭한다.

    int main(void)
    {
    	char ch[12] = { "Hello" };
    	char *pch = NULL;
    
    	// 메모리 동적 할당
    	pch = (char *)malloc(sizeof(ch) / sizeof(char));
    
    	// 포인터 변수에 ch 주소 단순 대입 (shallow copy)
    	// pch = ch;
    
    	// Deep copy
    	for (int i = 0; i < sizeof(ch) / sizeof(char); ++i){
    		*(pch + i) = ch[i];
    	}
    
    	puts(pch);
    
    	free(pch);
    
    }

    위의 코드는 pch 포인터가 가리키는 주소의 메모리로 접근해 해당 메모리에 ch 배열의 각 인스턴스들의 값을 단순 대입 한 것이다. 즉 pch 포인터가 가리키는 주소는 동적 할당 받은 메모리가 되고 따라서 동적 할당 받은 메모리에 ch 배열의 각 요소들의 값이 들어가게 된다. 이렇게 되면 성공적으로 동적 할당 받은 메모리에 사용자가 원하는 Hello 문자열 상수가 들어가게 된다.

    1. pch 포인터에 동적 할당 받은 메모리의 주소를 단순 대입

    2. 포인터 변수가 가르키는 주소의 메모리에 접근하여 해당 메모리의 값을 ch[i] 째에 해당하는 인덱스의 값으로 단순 대입 (0x 00526B50 주소의 메모리를 확인 하면 아래와 같이 ch배열의 각 요소들의 값이 성공적으로 복사됨)

     

     

     

     

     

     

     

     

     

     

    'C언어' 카테고리의 다른 글

    포인터의 이해  (0) 2020.03.07
    배열의 이해  (0) 2020.03.05
    메모리 동적 할당 및 해제  (0) 2020.03.04
    가상메모리  (0) 2020.03.03
    메모리의 구조와 포인터  (0) 2020.03.01

    댓글

Designed by Tistory.