안녕하세요. BlockDMask 입니다.
오늘은 C언어, C++에서 메모리를 복사하는 함수 memcpy 함수에 대해서 한번 알아보려 합니다.
지난시간에는 메모리를 초기화 하는 memset에 대해서 배웠던거 기억하시죠?
혹시 memset에 대해 궁금하다면 [바로가기]
그럼 오늘의 함수 memcpy 시작해보겠습니다.
<목차>
1. memcpy 함수란?
2. memcpy 함수 예제
1. 메모리 복사 memcpy 함수
memcpy는 memory + copy입니다. 즉 메모리의 값을 복사하는 기능을 하는 함수 입니다.
일단 함수의 모양을 보시죠.
헤더파일 C언어 <string.h>, C++ <cstring>
void* memcpy (void* dest, const void* source, size_t num)
첫번째 인자 void* dest
= 복사 받을 메모리를 가리키는 포인터
두번째 인자 const void* source
= 복사할 메모리를 가리키고 있는 포인터
세번째 인자 size_t num
= 복사할 데이터(값)의 길이(바이트 단위)
두번째 인자(source)에 있는 원본을 세번째 인자(num)만큼의 길이 만큼 복사해서
첫번째 인자(dest)에 붙여 넣는 함수 입니다.
다시 한번 이야기 해보면 memcpy(dest, source, num) 함수는 source의 메모리에 있는 값들을 num 길이만큼 dest에 복사해서 붙여넣는 함수 입니다.
자, 마지막으로 기억하기 좋게 강조하면 memcpy(복사받을 메모리, 복사할 메모리, 길이) 입니다.
**주의할점 1
길이를 계산할때 char* 타입의 C언어 문자열 형태의 문자열의 전체를 복사할때는 맨 뒤에 문자열의 끝을 알리는 "\0"의 길이도 계산해서 넣어야하기 때문에 +1의 길이만큼 해주어야합니다. 아래 예제에서 확인하시죠.
**주의할점 2
memcpy는 source 메모리 블록과 dest의 메모리 블록이 겹쳐져 있는 곳에서는 사용하지 못합니다. 즉 복사할 메모리랑, 복사 한 결과값을 붙여넣을 메모리가 겹쳐져 있다면 함수가 제대로 작동하지 않습니다. 만약 동일한 메모리 공간에 덮어씌워야 한다면 memmove 함수를 사용하면 됩니다.
memmove 함수 [바로가기]
but, 요즘엔 memcpy, memmove 둘다 동일하게 작동하긴 합니다.
2. memcpy 예제
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 30 | #include<string.h> #include<stdio.h> int main(void) { int src[] = { 1,2,3 }; int dest[3]; // 메모리 복사 memcpy(dest, src, sizeof(int) * 3); // memcpy(dest, src, sizeof(src)); sizeof(src)도 가능 // 복사한 배열 for (int i = 0; i < 3; ++i) { printf("%d ", src[i]); } printf("\n"); // 복사된 배열 for (int i = 0; i < 3; ++i) { printf("%d ", dest[i]); } return 0; } | cs |
예제를 보면 초기화 하지 않은 배열 dest에 src의 값이 잘 복사된것을 확인할 수 있습니다.
memcpy 함수에서 보여드렸듯
전체를 복사하려는 경우에는 세번째 인자에 sizeof(데이터 타입) * n 을 넣어도 가능하고 sizeof(배열)도 가능합니다.
전체를 복사하려는게 아니라면 sizeof(데이터 타입) * 복사할 길이 만 가능합니다.
char* 타입 복사1 : 일부만 복사
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include<string.h> #include<stdio.h> int main(void) { const char* src = "BlockDMask"; char dest[] = "abcdefghijklmnop"; // 메모리 복사 memcpy(dest, src, sizeof(char) * 6); // 여섯 자리만 복사 // source printf("%s ", src); printf("\n"); // destination printf("%s ", dest); return 0; } | cs |
이렇게 C언어 스타일의 문자열 (char*)을 복사 해보았습니다.
결과 화면을 보면 sizeof(char) * 6 이므로 6 자리만 복사된것을 확인 할 수 있습니다.
char* 타입 복사2 : 전체 복사 (주의)
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 | #include<string.h> #include<stdio.h> int main(void) { char src[] = "BlockDMask"; char dest1[] = "abcdefghijklmnop"; char dest2[] = "abcdefghijklmnop"; // 메모리 복사1 : src 길이만큼만 복사 memcpy(dest1, src, sizeof(char) * 10); // 메모리 복사2 : src 길이 + 1 만큼 복사 memcpy(dest2, src, sizeof(char) * 10 + 1); // source printf("src : %s\n", src); // destination printf("dest1 : %s\n", dest1); printf("dest2 : %s\n", dest2); return 0; } | cs |
결과를 보면 알 수 있듯이 C언어 스타일의 문자열(char*)을 전체 복사할때는 길이 + 1을 해주어야 합니다.
이미 다들 알고 있듯
const char* src = "BlockDMask"; 이것은 문자열의 끝에 문자열의 끝을 알리는 '\0'이 있기 때문에 이것까지 복사를 해주어야 딱 src 만큼 복사가 가능합니다.
그렇기 때문에 dest1는 "BlockDMask"까지만 복사 되어서 dest1이 "BlockDMaskklmnop" 가 되었고
dest2는 "BlockDMask\0" 까지 복사 되었기 때문에 "BlockDMask\0klmnop"가 되어서 출력할때는 앞에서부터 쭉 출력하다가 문자열의 끝을 알리는 '\0'를 만났기 때문에 "BlockDMask" 여기까지만 출력하게 된 것 입니다.
추가적으로 dest1과 dest2를 제대로 적으면
dest1 : "BlockDMaskklmnop\0"
dest2 : "BlockDMask\0klmnop\0"
이렇게 되겟죠?
프로그래머가 의도적으로 '\0'을 빼고 복사하려면 "sizeof(char) * 배열길이" 만큼만 복사하면 되고
'\0' 까지 복사를 하려면 "sizeof(char) * 배열길이 + 1" 까지 해주어야 합니다.
이상으로 C/C++의 메모리 복사 함수 memcpy에 대해서 알아보았습니다.
감사합니다.
'<개인공부> > [C언어, C++]' 카테고리의 다른 글
[C언어/C++] isspace 함수 (공백, 탭, 개행을 확인하는 함수) (0) | 2020.12.10 |
---|---|
[C언어/C++] isalpha 함수 (알파벳을 확인하는 함수) (1) | 2020.12.03 |
[C언어/C++] 삼각함수 sin, cos, tan 함수 설명 및 예제 (라디안 포함) (1) | 2020.11.26 |
[C언어/C++] memmove 메모리 이동 함수 설명 및 예시 (0) | 2020.11.19 |
[C언어/C++] memset 함수 메모리 초기화 (12) | 2020.11.05 |
[C언어/C++] 시간 관련함수에 대해서 (time, localtime, ctime, asctime) (6) | 2020.08.24 |
[C언어/C++] fgets, fputs 함수에 대해서 (2) | 2020.06.22 |
[C언어/C++] fputc, fgetc 함수에 대해서 (0) | 2020.06.16 |