---
# System prepended metadata

title: 2 Libft memfunction
tags: [Libft]

---

---
Category : Libft
Id : 2
Title : mem function(Libft)
Description : mem function
Date : 2020, 10, 16 (Fri)
Auther : seolim
tags : Libft
---




# 2 Libft memfunction

> Caution

본 문서를 포함한 블로그의 모든 내용은 <b>42 innovation academy</b>의 과제의 작성자의 해석 및 풀이 등으로 이루어져 있습니다.</br>본인이 42 교육생이거나 42 교육을 희망하는 분이라면 글을 먼저 보기보다는 고민해보고 읽어보기를 추천드립니다.

> 목적

mem 관련 함수들을 알아보자. 이번 과정에서 알아볼 함수들은 아래와 같다.

```c
void* memset (void* ptr, int value, size_t num );

void bzero(void *s, size_t n);

void* memcpy(void* destination, const void* source, size_t num);

void *memccpy(void *dest, const void *src, int c, size_t n);

void* memmove(void* destination, const void* source, size_t num);

void* memchr(const void* ptr, int value, size_t num);

int memcmp(const void* ptr1, const void* ptr2, size_t num);
```

> mem 함수들

mem함수는 메모리를 조작하는 함수들이며 `<string.h>`에 정의되어있다.(정확히는 memset, memcmp등은 `<memory.h>`에 정의되어 있으며 `<string.h>`에서 include 되어있다)</br></br>
mem함수들은 모두 사이즈(`size_t`)를 파라미터로 받는데, 문자열과 같이 마지막이 null문자라는 규칙같은게 없기 때문에 메모리의 마지막을 판단 할 수 없기 때문이다.</br></br>mem함수들은 string에 정의되어있기는 하지만 pointer면 어떤값이든 받아서 동작할 수 있다. 아래와 같이 int 배열에서도 동작한다.

```c
int nums[3] = {1, 2, 3};
int copy[3];

memcpy(copy, nums, sizeof(int) * 3);
/* int 배열은 한칸당 4bit의 크기를 가지기 때문에 위 같은 배열에선 12(sizeof(int) * 3)만큼의 크기를 복사해야 정상적으로 동작함을 꼭 기억하자
```


### memset
```c
void* memset(void* ptr, int value, size_t num);
```

<table>
    <tr>
        <td>ptr</td>
        <td>메모리 블럭의 첫번째 주소</td>
    </tr>
    <tr>
        <td>value</td>
        <td>할당할 값</td>
    </tr>
    <tr>
        <td>num</td>
        <td>할당할 크기</td>
    </tr>
    <tr>
        <td>return</td>
        <td>성공 : ptr / 실패 : NULL</td>
    </tr>
</table>

메모리 블럭(ptr)에 특정 값(value)를 특정 길이(size)만큼 할당한다. 성공하면 ptr을 반환하고 실패하면 NULL을 반환한다.

주로 초기화를 할 때 사용한다. 예를 들어 아래와 같이 활용한다.
```c
char  ptr[10];

memset(ptr, 0, 10);
```

위 코드가 실행되면 배열 ptr의 모든 값은 0으로 초기화 된다.

##### 왜 필요할까?
일반적으로 배열의 할당은 위처럼 선언을 통해 할당하거나 malloc등의 allocation함수를 통해 메모리를 할당한다. 해당 할당은 그저 일정 메모리를 변수에 할당해 주는것이기 때문에 그 값이 일정치 않다. 그러한 값을 쓰레기값(garbage value)라 한다. memset을 통해 최초의 값들을 모두 null값(0)등으로 초기화하여 에러를 방지한다.

### bzero
```c
void bzero(void *s, size_t n);
```
<table>
    <tr>
        <td>s</td>
        <td>메모리 블럭의 첫번째 주소</td>
    </tr>
    <tr>
        <td>n</td>
        <td>할당할 사이즈</td>
    </tr>
</table>

memset과 동일하게 동작하며 단 값이 모두 0이다. memset 예제와 동일하게 동작한다.

### memcpy
```c
void* memcpy(void* destination, const void* source, size_t num);
```
<table>
    <tr>
        <td>destination</td>
        <td>복사될 메모리 시작점</td>
    </tr>
    <tr>
        <td>source</td>
        <td>복사할 메모리 시작점</td>
    </tr>
    <tr>
        <td>num</td>
        <td>복사할 크기</td>
    </tr>
    <tr>
        <td>return</td>
        <td>destination</td>
    </tr>
</table>

지정된 크기만큼의 메모리의 값을 다른 메모리에 복사한다. 복사범위가 같으면 overflow문제가 발생할 수 있으며 관련내용은 [다음 글]()을 참고하자

##### 왜 필요할까?
포인터에 대한 이해가 명확하다면 값 복사가 왜 필요한지 알고 있을것이다. 아래 코드를 봤을 때, 결과가 어떻게 다를지를 생각해보자.

```c
char str1[] = "sample";
char *str2;
char *str3;

str2 = str;
memcpy(str3, str, 7);
/* 위 코드는 str3에 메모리가 할당되지 않아 strict한 환경에선 동작하지 않는다. 동작시키려면 str3에 미리 크기 7 이상의 동적할당을 하도록 하자*/
```
str2는 str1의 포인터를 그대로 할당받는다. 따라서 str1의 값이 변경되면 str2의 값도 함께 바뀐다. 즉 str1과 str2가 가르키고 있는 주소는 동일하다. 

### memccpy
```c
void *memccpy(void *dest, const void *src, int c, size_t n);
```
<table>
    <tr>
        <td>dest</td>
        <td>복사될 메모리 시작점</td>
    </tr>
    <tr>
        <td>src</td>
        <td>복사할 메모리 시작점</td>
    </tr>
    <tr>
        <td>c</td>
        <td>복사를 멈출 플래그 문자</td>
    </tr>
    <tr>
        <td>n</td>
        <td>복사할 메모리 크기</td>
    </tr>
    <tr>
        <td>return</td>
        <td>desc</td>
    </tr>
</table>

`memcpy`와 동일하나 정해준 특정 값(c)을 발견하면 복제를 멈춘다.

### memmove
```c
void* memmove(void* destination, const void* source, size_t num);
```
<table>
    <tr>
        <td>destination</td>
        <td>복사될 메모리 시작점</td>
    </tr>
    <tr>
        <td>source</td>
        <td>복사할 메모리 시작점</td>
    </tr>
    <tr>
        <td>num</td>
        <td>복사할 크기</td>
    </tr>
    <tr>
        <td>return</td>
        <td>destination</td>
    </tr>
</table>

`memcpy`와 기능은 완전히 동일하다. 다만 메모리 중간에 버퍼를 이용해 `memcpy`의 overflow 문제는 없다. [다음 글]()을 참고하자.

### memchr
```c
void* memchr(const void* ptr, int value, size_t num);
```
<table>
    <tr>
        <td>ptr</td>
        <td>복사될 메모리 시작점</td>
    </tr>
    <tr>
        <td>value</td>
        <td>찾을 값</td>
    </tr>
    <tr>
        <td>num</td>
        <td>찾아볼 메모리 범위</td>
    </tr>
    <tr>
        <td>return</td>
        <td>성공 : 일치되는 값의 주소 / 실패 : NULL</td>
    </tr>
</table>

주어진 메모리내에 원하는 특정값을 찾아 그 주소를 반환한다. 

### memcmp
```c
int memcmp(const void* ptr1, const void* ptr2, size_t num);
```
<table>
    <tr>
        <td>ptr1</td>
        <td>비교 메모리 블록 시작점</td>
    </tr>
    <tr>
        <td>ptr2</td>
        <td>비교 메모리 블록 시작점</td>
    </tr>
    <tr>
        <td>num</td>
        <td>비교할 범위</td>
    </tr>
    <tr>
        <td>return</td>
        <td>일치 : 0 / 불일치 : 다른값의 차(*ptr1 - *ptr2)</td>
    </tr>
</table>

두 메모리블록들의 값이 일치하는지를 비교하는 함수이다. 

##### 왜 필요할까?
메모리의 값을 비교하는데에 주의하면 된다. 아래 코드를 보자
```c
char str1[] = "test";
char str2[] = "test";

int equl = str1 == str2 ;
int cmp = memcmp(str1, str2, 4) == 0;
/*cmp는 값이 같으면 0을 반환하기 때문에 통일성을 위와 같이 작성하였다.*/
```

`eqaul`의 값은 0(`false`)이지만 `cmp`의 값은 1(`true`)이다. 포인터의 비교는 포인터의 주소가 동일한지 확인하는 것이기 때문에 위와같이 동작하게 된다. 앞서 말했던 값과 포인터의 차이를 잘 생각해보자.

