티스토리 뷰

728x90
반응형

 

(2021.01.03 내용 수정) dest와 src 전부 NULL일때 return (NULL)로 수정

2021.01.07 내용 업데이트
2021.12.02 memmove 내용 수정

 

💡 memcpy에 대하여

환경

  • c, c++
  • c++에서는
  • c에서는 <string.h>




Prototype

void    *memcpy(void *dest, const void *src, size_t num);
  • dest : 채우고자 하는 메모리의 시작 포인터(시작 주소)
  • src : 메모리에 채우고자 하는 값, int형 이지만 내부에서는 unsigned char(1 byte)로 변환되어서 저장된다.
  • num : 채우고자 하는 바이트의 수. 즉, 채우고자 하는 메모리의 크기
  • memcpy함수의 인자인 source 가 가리키는 곳 부터 num 바이트 만큼을 destination 이 가리키는 곳에 복사한다.



 

memcpy 목적

memcpy함수의 인자인 source 가 가리키는 곳 부터 num 바이트 만큼을 destination 이 가리키는 곳에 복사한다.

이 때, destinationsource 의 타입은 모두 위 함수와 무관하다. 왜냐하면 이 함수는 단순히 이진 데이터를 복사하는 것이기 때문이다. 또한, 이 함수는 source널 종료 문자(null terminating character) 을 검사하지 않는다. 언제나 정확히 num 바이트 만큼을 복사한다.

오버플로우 문제를 방지하기 위해 destinationsource 가 가리키는 배열의 크기는 반드시 num 바이트 이상이여야 하며, 서로 겹치면 안된다. (만일 두 메모리 블록이 겹쳐져 있다면 memmove 함수를 이용하는 것이 현명하다)



strcpy와 차이점

strcpy 는 문자열 복사를 위한 함수로서
길이를 지정안하는 대신 source 문자열이 반드시 '\0' 으로 끝나야합니다.
source 에서 '\0'을 만나면 복사를 종료합니다
('\0' 까지 복사됩니다)

이에 반하여 memcpy는 형에 관계없이 임의의 영역을 지정한 byte 수만큼 복사하는
기능을 수행합니다

char dstS[64], srcS[]="string copy";

여기서 srcS를 dstS로 복사하려면

strcpy 로는

strcpy(dstS, srcS);

이렇게만 하면 되지만

memcpy로 복사하려면

memcpy(dstS, srcS, strlen(srcS)+1);

'\0' 까지 처리하기위해 복사할 size를 strlen(srcS)+1 로 지정해 줘야합니다

둘다 메모리 복사란 점에서는 같은 역할을 하지만
문자값을 비교하여 종료하느냐, byte 수를 따져 종료하느냐의 차이가 있습니다
용도가 틀리다고 말할 수는 있어도 어떤것이 더 효율적이다라고는 말하기 어렵습니다
memcpy쓸곳에는 memcpy를 쓰고 strcpy를 쓸 곳에는 strcpy를 쓰면 된다.

출처 : https://blog.naver.com/kihoyaa/10000790352



 

Return Value

  • memcpy()함수는 dest에 대한 포인터를 return 합니다.
  •  




memcpy 함수의 구현

#include <string.h> //NULL과 size_t를 쓰기 위한 헤더
void    *ft_memcpy(void *dest, const void *src, size_t num)
{
    size_t i;

    i = 0;
    if (!num || dest == src)        //num이 0, dest == src인 경우
        return (dest);
    if (dest == NULL && src == NULL)    //src와 dest null인 경우엔 null
        return (NULL);
    while (i < num)
    {
        ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
        i++;
    }
    return (dest);
}
사용예제
int src[] = { 1,2,3 };
int dest[3];
// 메모리 복사
memcpy(dest, src, sizeof(int) * 3);
// memcpy(dest, src, sizeof(src)); sizeof(src)도 가능



 




 

💡 memccpy에 대하여

환경

  • c, c++
  • c에서는 <string.h>




Prototype

void    *memccpy(void *dest, const void *src, int c, size_t num);
  • dest : 채우고자 하는 메모리의 시작 포인터(시작 주소)
  • src : 메모리에 채우고자 하는 값, int형 이지만 내부에서는 unsigned char(1 byte)로 변환되어서 저장된다.
  • c : 리눅스의 man에서는 char c를 마주치면 동작을 멈춘다고 명시 돼 있다. unsigned char 로 변환된다고 한다.
  • num : num만큼의 복사를 한다.



 

memccpy 목적

  • memccpy : c문자를 찾을때까지 src문자열을 dest에 복사한다. 만약 c를 찾으면 dest의 c와 일치하는 다음 주소값을 반환하고, src의 값에서 n만큼 중 c를 찾지 못하면 NULL 값을 반환한다.
  • (linux man)

 



 

Return Value

  • memccpy()함수는 dest에 대한 포인터를 return 합니다.




memccpy 함수의 구현

#include <string.h> //NULL과 size_t를 쓰기 위한 헤더
void    *ft_memccpy(void *dest, const void *src, int c, size_t num)
{
    size_t i;

    i = 0;
    if (!dest && !num)
        return ((void *)0);
    while (i < num)
    {
        ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
        if ((unsigned char)c == ((unsigned char *)src)[i])
            break ;
        i++;
    }
    if (num == i)
        return ((void *)0);
    return (dest + i + 1);
}



 

💡 memmove에 대하여

환경

  • c, c++
  • c에서는 <string.h>




Prototype

void    *ft_memmove(void *dest, const void *src, size_t n)
  • dest : 채우고자 하는 메모리의 시작 포인터(시작 주소)
  • src : 메모리에 채우고자 하는 값, int형 이지만 내부에서는 unsigned char(1 byte)로 변환되어서 저장된다.
  • n : 복사하고자 하는 크기(bytes)



 

memmove 목적

  • memmove : 입력받은 src 메모리를 dest에 복사한다. 단, 영역이 겹치는 경우가 발생한다.
  • 임의로 메모리의 값을 이동시켜주는 과정이기에 메모리의 영역이 겹치는 경우가 생긴다. linux man에서는 임시 temp 배열을 만들어서 src 값을 복사해준 뒤, dest에 다시 넣어주라고 설명이 되어있다. 내 코드에서는 src의 포인터가 dest보다 작은 경우에 끝의 배열을 먼저 복사해줌으로 해결했다.
  • dest의 할당된 주소값이 만약 100이고, src의 주소값이 96이라고 가정하자. dest의 주소값에는 src의 값이 저장 돼 있을 수도 있다. 이런 경우에는 원본의 데이터를 갱신하기 때문에, 기존의 값을 제대로 복사를 할 수 없다. 이런 경우를 예외처리 해줘야 한다.



 

Return Value

  • memmove()함수는 dest에 대한 포인터를 return 합니다.




memmove 함수의 구현

#include <string.h> //NULL과 size_t를 쓰기 위한 헤더
void    *ft_memmove(void *dest, const void *src, size_t num)
{
    size_t i;

    if (dest == NULL && src == NULL)
        return (NULL);
    if (dest < src)
    {
                 /*
                 * src 의 주소가 dest 보다 큰 값이면,
                 * src 의 처음 부터 count 만큼 dest 에 복사한다.
                 * src를 한 byte씩 복사하더라도 dest 보다 큰 위치에 있기 때문에,
                 * 오버랩되더라도 src 를 모두 정상적으로 dest에 복사할수 있다.
                 */
        i = 0;
        while (i < num)
        {
            ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
            i++;
        }
    }
    else
    {
                /*
                 * src의 주소가 dest 보다 작은 값이면,
                 * src 의 마지막 데이터부터 한바이트씩 dest의 마지막 바이트부터
                 * 순서대로 복사한다.
                 */
        i = num;
        while (i)
        {
            ((unsigned char *)dest)[i - 1] = ((unsigned char *)src)[i - 1];
            i--;
        }
    }
    return (dest);
}
    사용예제
    int src[] = { 7, 6, 5, 4, 3, 2, 1};
    int dest[7];

    memmove(dest, src, sizeof(src));

 

 

틀린 내용이나 지식이 있다면 댓글로 알려주세요! 감사합니다!

 

 

📕 reference :

예비 개발자의 일상

모두의 코드 reference

man linux

일상메모장

728x90
반응형
댓글