void* memcpy(void* dest, const void* src, size_t count);
매개변수(인자)
void* dest = 복사 데이터를 받을 주소
const void* src = 원본 주소
size_t count = 복사할 데이터의 크기 (바이트)
반환값(리턴값)
void* = dest가 반환된다.
설명
* src를 시작점으로 count 바이트만큼 복사해서 dest에 집어넣는다.
* 바이너리(이진법) 형태로 복사하기 때문에 널문자로 같이 복사될 뿐이다.
* 무식하게 복사하기 때문에 양쪽에 자료형이 뭔지 상관없다. 그냥 복사한다.
* 오버플로우가 일어날 수 있다.
* #include <string.h>를 해야 한다.
예제
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char a[5] = "abcd";
int b = 0;
int* p_b = &b;
memcpy(p_b, a, 4);
}
* 자료형이 달라도 안에 16진 수로 된 값이 같은 것을 알 수 있다.
void* realloc(void* ptr, size_t new_size);
매개변수(인자)
void* ptr = 이미 할당된 메모리 주소
size_t new_size = 새로 설정할 메모리 크기 (바이트)
반환값(리턴값)
* 원래 주소 or 새로운 주소 (기존 메모리를 해제한다.)
실패 시 NULL을 반환 (기존 메모리를 해제하지 않는다.)
설명
* 이미 할당된 메모리의 크기를 new_size로 바꿔준다.
* 원래 메모리보다 더 작은 크기를 할당했을 때 데이터 손실이 발생한다.
* 기존 메모리 해제는 생각할 필요가 없다. (필요하면 알아서 해줌)
주의!
array_p = realloc(array_p, 1000); 을 했을 때 오류가 나서 NULL을 반환 할 경우
array_p에 NULL이 들어가서 원래 메모리 주소를 없애버리는 경우가 발생할 수 있다.
해결책!
매개변수로 넣는 포인터와 반환값을 넣을 포인터 변수를 따로 두는 것이 안전하다.
realloc(NULL, new_size);
* 새로운 메모리를 할당한다.
* malloc과 동일하게 작동됨.
성능
* realloc 함수를 구현한다면
1. malloc(new_size); 원하는 크기를 할당한다.
2. memcpy(dest, src, src_size); 원본 데이터를 dest에 복사한다.
3. free(src); 기존 메모리를 해제한다.
이런 방법은 기존 메모리도 가지고 있는 상태에서 새로운 메모리를 만들 수 있다는 장점이 있다.
(다르게 말하면 realloc은 기존 메모리가 필요없을 때 사용하는 거라고 말할 수 있다.)
* realloc은 위에서 설명한 구현보다 더 빠르거나 같다.
왜냐하면 realloc이 반환하는 주소가 동일하다는 것은 메모리의 크기만 늘린것일 뿐
복사가 일어나지 않았다는 증거이다.
예제
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* array = malloc(20);
char* array_p = array;
strcpy(array_p, "abcdef");
char* new_p = realloc(array_p, 1000);
printf("%p\n", array);
printf("%p\n", array_p);
printf("%p\n", new_p);
printf("%s\n", array);
printf("%s", new_p);
}
* realloc 함수가 포인터 값을 바꾸지 않았다.
* 새로 할당된 메모리 주소가 바뀔 수도 아닐 수도 있다.
* realloc 함수가 데이터또한 복사해준다.
안전한 realloc 사용
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
void* origin;
int size = 10;
int new_size = size * 2;
origin = malloc(size);
void* tmp = realloc(origin, new_size);
if (tmp != NULL) {
origin = tmp;
}
/* origin을 사용 후*/
free(origin);
}
* 다른 포인터에 담았다가 NULL이 아니라면 기존 포인터 변수로 옮긴다.
* free를 사용할때 기존 포인터 변수를 해제하는 것이 더 명확해 보인다.
귀여운 그림은 낡은 창고님이 그리셨습니다.