<개인공부>/[C언어, C++]

[C언어/C++] memmove 메모리 이동 함수 설명 및 예시

BlockDMask 2020. 11. 19. 00:30
반응형

안녕하세요. BlockDMask 입니다
오늘은 C, C++에서 메모리 이동을 하는 함수 memmove 라는 함수에 대해서 알아보려고 합니다.
지난시간과 지지난시간에는
메모리를 초기화 하는 memset 함수메모리를 복사하는 memcpy 함수를 배웠죠?
오늘은 memcpy와 항상 함께 언급되는 memmove라는 함수입니다.

<목차>
1. memmove 함수란?
2. memmove 함수 예제


1. 메모리 이동 memmove 함수


memmove는 memory + move를 합쳐서 만든 함수 이름 입니다.
매우 명확하게 함수 이름에서 우리는 함수의 기능을 생각해볼수 있습니다.
"메모리를 이동한다." 라는 것을요. 그럼 자세하게 무엇을 어떻게 이동하는지 알아보죠.

헤더파일 : C언어 <string.h>, C++ <cstring>

void* memmove (void* dest, const void* src, size_t num);

첫번째 인자 void* dest
= destination.
복사 한걸 붙여넣을 메모리를 가리키는 포인터 입니다. (목적지)

두번째 인자 void* src
= source.
복사 할 메모리를 가리키는 포인터 입니다. (출발지)

세번째 인자 size_t num
= 복사할 바이트 길이 입니다.

반환형
= 첫번째 인자인 dest를 반환 합니다.

함수 설명.
 src가 가리키는 메모리로 부터 num 바이트 사이즈 만큼 dest가 가리키는 메모리에 옮깁니다.
  move 라서 잘라내고 붙여넣는다고 생각하실수 있지만, 이것도 복사하는 기능을 가진 함수 입니다.
그러면 복사 만 하는거면 memcpy와 같다고 생각하실 수 있겠지만, 
memcpy는 바로 그냥 어디 거치지 않고 그 위치에 복사해서 붙여넣는다고 생각하시면 되고,
 memmove는 그것보다는 안전하게, 복사할것을 버퍼에 복사하고 해당 위치에 가서 버퍼에 복사된 것을 붙여 넣는 식으로 동작이 구현되어있습니다.
성능을 "굳이" 따지자면 memcpy가 버퍼를 거치지 않고 복사하기 때문에 좀더 좋긴 하겠지만, 버퍼를 이용하는 memmove가 더 안정성이 좋습니다.

자, 정리해보겠습니다.
memmove 함수도 메모리를 src에서 dest로 num 바이트 길이만큼 복사하는 함수이다.
하지만, 중간에 버퍼를 이용해서 복사를 하므로 안정성이 memcpy 보다는 뛰어나다.
memmove의 생김새는 아래와 같다.
memmove(void* dest, void* src, size_t num);
이제 예제로 가볼까요?

2. 메모리 이동 memmove 함수 예제


memmove 예제1 : int* 타입

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<string.h>
#include<stdio.h>
 
int main(void)
{
    int src[] = { 7654321};
    int dest[7];
 
    // 메모리 복사 (전체)
    memmove(dest, src, sizeof(src));
    //memmove(dest, src, sizeof(int) * 7); // 이것도 가능
    
    // 복사한 배열
    for (int i = 0; i < 7++i)
    {
        printf("%d ", src[i]);
    }
 
    printf("\n");
 
    // 복사된 배열
    for (int i = 0; i < 7++i)
    {
        printf("%d ", dest[i]);
    }
 
    return 0;
}
 
cs

이렇게 배열의 전체를 복사할때는 예제에서 보신것과 같이 바이트 길이를 따로 계산할 필요 없이 sizeof(배열)을 이용해서 길이를 넘겨주는 것도 매우 간편합니다.

src 에 있는 배열의 값들이 dest로 잘 복사 되는것 확인하셨나요?
이렇게 간편하게 사용할 수 있습니다. 그럼 다음예제로 가보시죠.


memmove 예제2 : 문자열 (char*)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<string.h>
#include<stdio.h>
 
int main(void)
{
    char src[] = "BlockDMask";
    char dest1[] = "fffffdddddzzzzz";
    char dest2[] = "fffffdddddzzzzz";
    char dest3[] = "fffffdddddzzzzz";
 
    // 메모리 복사1 : src 길이만큼만 복사
    memmove(dest1, src, sizeof(char* 10);
 
    // 메모리 복사2 : src 길이 + 1 만큼 복사
    memmove(dest2, src, sizeof(char* 10 + 1);
 
    // 메모리 복사3 : 메모리 일부 복사
    memmove(dest3 + 10, src, sizeof(char* 3);
 
    // source
    printf("src  : %s\n", src);
 
    // destination
    printf("dest1 : %s\n", dest1);
    printf("dest2 : %s\n", dest2);
    printf("dest3 : %s\n", dest3);
 
    return 0;
}
 
cs

예제1 : 문자열의 길이 만큼만 복사하게 되면 char*, char [] 문자열의 끝에 있는 \0을 복사하지 않고 순수 문자들만 복사하게 됩니다. 그렇기 때문에 dest1의 값은 뒤에있는 zzzzz 까지 잘 나오는 것을 볼 수 있습니다.

예제2 : 여기를 보면 src 길이 + 1 까지 복사를 해버리니 문자열 끝을 알려주는 \0 까지 복사를 하게 됩니다. 그렇게 되면 dest2는 "BlockDMask\0zzzz" 가 되기 때문에 이 문자열을 출력할때 \0 까지만 출력이 되는 상황이 발생합니다.
예제1, 2번을 보고 개발을 하실때 본인의 의도에 맞게 복사를 하시기 바라겠습니다.

예제3 : src 에서 char 바이트 만큼 3개를 복사해서 dest3의 +10번 위치에 복사를 했습니다.
결과값을 보면 dest3 배열에서 +10 만큼 뒤쪽에 src 배열의 3개의 문자가 잘 복사되는것을 확인 할 수 있습니다.



memmove 예제3 : 자기 자신의 위치에 복사

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<string.h>
#include<stdio.h>
 
int main(void)
{
    char str[] = "BlockDMask";
 
    // 메모리 복사 : 메모리 겹침
    memmove(str, str + 2sizeof(char* 4);
 
    // source
    printf("src  : %s\n", str);
 
    return 0;
}
 
cs

예제를 보면 
src를 가리키는 두번째 인자가 가리키는 배열과 dest를 가리키는 첫번째 인자가 가리키는 배열이 동일한 배열에 존재합니다.
그리고, 복사할 위치와 붙여넣기할 위치가 겹치는 상황입니다.
하지만 우리의 memmove는 당황하지 않고 침착하게 str + 2 위치에서부터 4개의 문자 "okcD"를 복사해서 목적지인 str에 붙여넣습니다. 그렇게 "BlockDMask"라는 문자열이 "okcDkDMask" 문자열이 되었습니다.


memmove 함수에 대해서도 알아 보았습니다.
이렇게 해서, C언어 C++에서 메모리 관련함수 3대장 memset, memcpy, memmove에 대해서 다 알아보았습니다.
감사합니다. 도움이 되었으면 하트 한번씩 눌러주시면 감사하겠습니다.
그럼 또 좋은 글로 돌아오겠습니다.

반응형