Libc는 C표준 라이브러리를 의미한다.
즉, C표준 라이브러리에 정의되어 있는 함수들을 재구현 해야한다.
memset
: 원하는 값으로 메모리 세팅bzero
: 메모리를 0으로 세팅memcpy
: src
가 가리키는 곳 부터 n
바이트 만큼을 dest
이 가리키는 곳에 복사한다.memccpy
: 메모리 영역 src
에서 메모리 영역 dest
로 n 바이트를 넘지 않고, 문자 c 가 발견되면 멈춘다.memmove
: src
가 가리키는 메모리로 부터 n바이트 사이즈만큼 dest
가 가리키는 메모리로 복사한다.memchr
: 메모리 블록에서 문자를 찾는다.memcmp
: 두 개의 메모리 블록을 비교한다.calloc
: malloc 처럼 메모리를 할당하고 전부 0으로 초기화한다.strlen
: 문자열의 길이를 구한다.
strlcpy
: null을 보장하면서 문자열을 복사한다.
strlcat
: null을 보장하면서 문자열을 이어 붙인다.
strchr
: 문자열에서 특정한 문자가 가장 먼저 나타나는 곳의 위치를 찾는다.
strrchr
: 문자열에서 특정한 문자를 검색하되 가장 마지막으로 나타나는 위치를 찾는다.
strnstr
: 문자열 내에서 부분문자열을 탐색한다.
strncmp
: 두 문자 열의 일부 문자열을 비교한다.
strdup
: 문자열을 새로운 메모리에 할당하여 복사한다.
isalpha
: 해당 문자가 알파벳인지 확인한다. (문자열x)isdigit
: 숫자인지 확인한다.isalnum
: 알파벳이거나 숫자인지 확인한다.isascii
: 아스키코드(0 ~ 127)인지 확인하다isprint
: 출력가능한 문자인지 확인한다.(아스키코드상 32~126 까지만 출력이 가능하다.)atoi
: 문자열 정수를 int형 정수로 변환한다.toupper
: 문자를 소문자에서 대문자로 변환한다.tolower
: 문자를 대문자에서 소문자로 변환한다.상수 바이트로 메모리 채우기
#include <string.h>
void *memset(void * ptr, int value, size_t n);
ptr
이 가리키는 메모리 영역의 첫 번째 부터 n
바이트를 상수 바이트 value
로 채운다.ptr
: 값을 채울 메모리의 시작 주소
value
: 채울 값, 인자로는 int
로 전달되지만 함수 내부적으로 unsigned char
로 형변환 되어서 사용된다.
n
: value
로 채울 바이트 수
ptr
이 리턴된다.#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char str[] = "almost every programmer should know memset!"; // 문자열(포인터) 선언 및 초기화
long long *numPtr = malloc(sizeof(long long)); // long long의 크기 8바이트만큼 동적 메모리 할당
memset(str, '-', 6); // 문자열(포인터) str에 첫번째부터 6번째 까지
printf("%s\n", str);
memset(numPtr, 0x27, 8); // numPtr이 가리키는 메모리를 8바이트만큼 0x27로 설정
printf("%llx\n", *numPtr); // 0x2727272727272727: 27이 8개 들어가 있음
free(numPtr); // 동적으로 할당한 메모리 해제
return 0;
}
void *ft_memset(void *ptr, int value, size_t n)
{
// ptr에서 1바이트씩 이동하면서 값을 할당해줘야한다. 즉 포인터 연산을 해야한다.
// 하지만 ptr이 void 포인터이므로 포인터 연산이 불가능하다. (자료형을 모르기 때문에)
// 따라서 ptr을 타입캐스팅을 한 후 자료형 포인터로 변환하여 포인터연산을 하던가
// 임시로 생성한 자료형 포인터 변수를 만들고 ptr을 가르키도록 하여 포인터 연산을 해야한다.
// 특히 왜 unsined char자료형을 사용하냐면,
// 1바이트씩 증가시키기위해, 자료형의 크기가 1바이트인 char로 하고
// 일반적인 char로 할 경우 자료형 연산을 할때 음수 때문에 얘기치 못한 불상사를 막기위함이다.
// char vs unsigen char 둘의 차이에 대한 이해가 더 필요하다.
// 왜 굳이 unsigen char 자료형을 써야할까
unsigned char *temp;
size_t i;
temp = ptr;
i = 0;
while (i < n)
{
temp[i] = value;
i++;
}
return (ptr);
}
제로 값의 바이트를 기입한다
#include <string.h>
void bzero(void *ptr, size_t n);
ptr
의 처음부터 n바이트까지 0으로 세팅한다.ptr
: 값을 채울 메모리의 시작 주소
n
: value
로 채울 바이트 수
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char str1[] = "almost every programmer should know memset!";
bzero(str1, 1);
printf("bzero : %s\n", str1);
return (0);
}
void ft_bzero(void *ptr, size_t n)
{
unsigned char *temp;
size_t i;
temp = ptr;
i = 0;
while (i < n)
{
temp[i] = 0;
i++;
}
}
메모리의 일부분을 복사한다.
#include <string.h>
void *ft_memcpy(void *dst, const void *src, size_t n);
src
가 가리키는 곳 부터 n
바이트 만큼을 dest
이 가리키는 곳에 복사한다.dst
와 src
의 타입은 모두 memcpy()
함수와 무관하다.src
의 null
종료 문자를 검사하지 않는다. 언제나 정확히 n
바이트 만큼 복사한다. (null보장 x)dst
와 src
가 가리키는 배열의 크기는 반드시 n
바이트 이상이어야 한다. (n < len(dest) && n < len(src)
) memmove()
함수를 사용하자.dst
: 데이터가 복사될 곳의 주소로, void*
형으로 형 변환 되어서 전달된다.src
: 복사할 데이터들이 위치한 주소로 역시 void*
형으로 형 변환 되어서 전달된다.n
: 복사할 데이터의 바이트 수 이다.dest
가 리턴된다.
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Sample string";
char str2[40];
char str3[40];
memcpy(str2, str1, strlen(str1) + 1);
memcpy(str3, "copy successful", 16);
printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
return 0;
}
void *ft_memcpy(void *dst, const void *src, size_t n)
{
size_t i;
if (dst == 0 && src == 0)
return (dst);
i = 0;
while (i < n)
{
((unsigned char*)dst)[i] = ((unsigned char*)src)[i];
i++;
}
return (dst);
}
메모리 영역 복사
#include < string.h >
void *memccpy(void *dest, const void *src, int c, size_t n);
NULL
값을 반환한다.#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Sample string";
char str2[40];
char str3[40];
int *res1 = memccpy(str2, str1, 's', strlen(str1) + 1);
int *res2 = memccpy(str3, "copy successful", 'u', 14) ;
printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
printf("res1 : %p\nres2 : %p", res1, res2);
return 0;
}
void *ft_memccpy(void *dest, const void *src, int c, size_t n)
{
unsigned char *tmp_dst;
unsigned char *tmp_src;
size_t i;
// const가 아닌 void 포인터 dest는 unsigned char 포인터형 tmp_dest에 할당 할때 암묵적 형변환이 되어 할당된다.
// 색이 옅은 void가 색이 있는 char로 형변환이 되는듯? 이부분은 좀더 확실하게 찾아보고 넘어가야 할 듯 하다.
// tmp_dest = (unsigned char*)dest; 이런식으로 타입캐스팅을 하고 할당해도된다.
// 반면에 const로 선언된 void 포인터 src는 타입캐스팅을 하지않고 할당하면 에러를 뱉는다.
tmp_dst = dst;
tmp_src = (unsigned char*)src;
i = 0;
while (i < n)
{
tmp_dst[i] = tmp_src[i];
if (tmp_src[i] == (unsigned char)c)
return (&dst[i + 1]);
i++;
}
return (0);
}
메모리 블록을 옮긴다.
#include <string.h>
void *memmove(void *dst, const void *src, size_t n);
src
가 가리키는 메모리로 부터 n바이트 사이즈만큼 dst
가 가리키는 메모리로 옮긴다.dst
과 src
의 해당하는 범위가 겹쳐져도 문제는 없다.src
의 널 종료 문자를 확인하지 않는다. 언제나 정확히 n
바이트 만큼 복사를 수행한다.dst
와 src
가 가리키는 배열 모두 적어도 n
바이트 이상은 되어야 한다.dest
: 복사 한걸 붙여넣을 메모리를 가리키는 포인터 (목적지)src
: 복사 할 메모리를 가리키는 포인터 (출발지)n
: 복사할 바이트 길이dest
가 반환이 된다.#include<string.h>
#include<stdio.h>
/*
예시1
memmove can be very useful...... 에서, 문자열 시작 주소 부터 15 번째 부분 부터
11 바이트, 즉 "very useful" 을 문자열 시작 주소 부터 20 번째 부분, 즉 "use~"
부분에 복사해 넣는다. 다시말해, 위 문자열은 "memmove can be very very useful."
이 된다.
*/
// 이 예시를 보면 정말 move한 느낌이 들긴 하다.
int main() {
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
// 예시2
int main(void)
{
int src[] = { 7, 6, 5, 4, 3, 2, 1};
int dest[7];
memmove(dest, src, sizeof(src));
//memmove(dest, src, sizeof(int) * 7); // 이것도 가능
printf("복사한 배열 : ");
for (int i = 0; i < 7; ++i)
{
printf("%d ", src[i]);
}
printf("\n");
printf("복사된 배열 : ");
for (int i = 0; i < 7; ++i)
{
printf("%d ", dest[i]);
}
return 0;
}
void *ft_memmove(void *dst, const void *src, size_t n)
{
unsigned char *tmp_dst;
unsigned char *tmp_src;
unsigned int i;
if (!dst && !src)
return (dst);
tmp_dst = (unsigned char*)dst;
tmp_src = (unsigned char*)src;
i = 0;
if (dst < src)
{
while (i < n)
{
tmp_dst[i] = tmp_src[i];
i++;
}
}
else
{
while (i < n)
{
tmp_dst[n - 1 - i] = tmp_src[n - 1 - i];
i++;
}
}
return (dst);
}
memmove() 전
0x0000(dest) | 0x0001 | 0x0002(src) | 0x0003 | 0x0004 | 0x0005 |
---|---|---|---|---|---|
t | e | s | t |
memmove() 후
0x0000(dest) | 0x0001 | 0x0002(src) | 0x0003 | 0x0004 | 0x0005 |
---|---|---|---|---|---|
t | e | s | t | s | t |
memmove() 전
0x0000(src) | 0x0001 | 0x0002(dest) | 0x0003 | 0x0004 | 0x0005 |
---|---|---|---|---|---|
t | e | s | t |
memmove() 후
0x0000(src) | 0x0001 | 0x0002(dest) | 0x0003 | 0x0004 | 0x0005 |
---|---|---|---|---|---|
t | e | t | e | s | t |
void *ft_memmove(void *dst, const void *src, size_t len)
{
unsigned char *usrc;
unsigned char *udst;
unsigned char temp[len];
if (dst == NULL && src == NULL)
return (NULL);
usrc = (unsigned char *)src;
udst = (unsigned char *)dst;
ft_memcpy(temp, usrc, len);
ft_memcpy(udst, temp, len);
return (dst);
}
기존에 작성한 코드는 버퍼개념을 이용하지 않았다. 이번에 tmp라는 임시장소(버퍼역할)로 옮기는걸로 조금더 간단하게 구현해보았다.
하지만 이렇게 구현하면 libft-unit-test
에서 128mb input data를 처리할 수 없다고 나오는데 왜 그런지는 아직 모르겠다.
메모리 블록에서 문자를 찾는다.
#include <string.h>
void *memchr(void *ptr, int value, size_t n);
ptr
: 검색을 수행할 포인터value
: 찾을 값으로, int
로 값이 전달되지만 내부적으로는 한바이트씩 비교하기 때문에 unsigned char
로 변환되어 사용된다.n
: 검색을 시작한 부분 부터 검색을 수행할 만큼의 바이트수value
와 일치하는 값이 있다면 그 곳의 주소를 리턴하고 값을 찾지 못한다면 NULL
을 리턴한다.#include <stdio.h>
#include <string.h>
int main() {
char* pch;
char str[] = "Example string";
pch = (char*)memchr(str, 'p', strlen(str));
if (pch != NULL)
{
printf("'p' found at position %ld.\n", pch - str + 1);
printf("pch : %p str : %p\n", pch, str);
}
else
printf("'p' not found.\n");
return 0;
}
void *ft_memchr(void *ptr, int value, size_t n)
{
unsigned char *tmp_ptr;
unsigned char find;
unsigned int i;
tmp_ptr = (unsigned char*)ptr;
find = (unsigned char)value;
i = 0;
while (i < n)
{
if (tmp_ptr[i] == find)
return (&tmp_ptr[i]);
i++;
}
return (0);
}
두 개의 메모리 블록을 비교한다.
#include <string.h>
int memcmp(const void *ptr1, const void *ptr2, size_t n);
ptr1값 - ptr2값
을 리턴한다.strncmp
와의 차이점?memcpy
는 두 문자열 중 하나가 끝나더라도(널 값이 나오더라도) 상관없이 서로 다른 값이 나오거나, n개가 될 때 까지 비교를 수행한다.strncmp
는 s1과 s2가 모두 NULL값이 나오면 남은 카운트에 관계없이 0을 반환한다.ptr1
: 메모리 블록을 가리키는 포인터
ptr2
: 메모리 블록을 가리키는 포인터
num
: 비교할 바이트 수
ptr1값 - ptr2값
을 리턴한다.#include <stdio.h>
#include <string.h>
int main ()
{
char str1[12];
char str2[12];
int state;
strcpy(str1, "mozi");
strcpy(str2, "tistory");
state = memcmp( &str1, &str2, 4 );
printf ("State=\"%d\", str1=\"%s\", str2=\"%s\"\n", state, str1, str2);
return 0;
}
int ft_memcmp(const void *ptr1, const void *ptr2, size_t n)
{
unsigned char *tmp_ptr1;
unsigned char *tmp_ptr2;
unsigned int i;
tmp_ptr1 = (unsigned char*)ptr1;
tmp_ptr2 = (unsigned char*)ptr2;
i = 0;
while (i < n)
{
if (tmp_ptr1[i] != tmp_ptr2[i])
return (tmp_ptr1[i] - tmp_ptr2[i]);
i++;
}
return (0);
}
문자열의 길이를 구한다.
#include <string.h>
size_t strlen(const char *str);
string
: C 형식 문자 or C 형식 문자열
문자열의 길이. (참고로 size_t
형으로 선언 되어 있는데 대부분의 string.h 에서는 부호 없는 정수형으로 선언되어 있다.)
#include <stdio.h>
#include <string.h>
int main() {
char szInput[256];
printf("Enter a sentence: ");
scanf("%s", szInput);
printf("The sentence entered is %lu characters long.\n", strlen(szInput));
return 0;
}
#include <stdlib.h>
size_t strlen(const char *str)
{
size_t i;
i = 0;
while (str[i])
i++;
return (i);
}
null을 보장하여 문자열 복사하기
#include <string.h>
size_t ft_strlcpy(char *dst, char *src, size_t size)
#include <stdlib.h>
size_t ft_strlcpy(char *dst, char *src, size_t size)
{
size_t i;
size_t src_len;
src_len = ft_strlen(src);
if (size == 0)
return (src_len);
i = 0;
while (src[i] && i < size - 1)
{
dst[i] = src[i];
i++;
}
dst[i] = 0;
return (src_len);
}
null을 보장하여 문자열 이어 붙이기
#include <string.h>
size_t ft_strlcat(char *dst, char *src, size_t size);
size_t ft_strlcat(char *dst, char *src, size_t size)
{
size_t dst_len;
size_t result;
size_t i;
dst_len = ft_strlen(dst);
result = ft_strlen(src);
i = 0;
if (size <= dst_len)
return (result + size);
while (src[i] && i < (size - dst_len - 1))
{
dst[dst_len + i] = src[i];
i++;
}
dst[dst_len + i] = 0;
result += dst_len;
return (result);
}
문자열에서 특정한 문자가 가장 먼저 나타나는 곳의 위치를 찾는다.
#include <string.h> // C++ 에서는 <cstring>
char *ft_strchr(const char *s, int c);
s
: C 형식 문자열
character
: 검색할 문자로, int
형태로 형변환 되어서 전달되지만 함수 내부적으로는 다시 char
형태로 처리된다.
s
에서 처음으로 발견되는 c
의 포인터를 리턴한다.
만일 문자가 없다면 NULL
포인터를 리턴하게 된다.
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "This is a sample string";
char* pch;
printf("Looking for the 's' character in \"%s\"...\n", str);
pch = strchr(str, 's');
while (pch != NULL) {
printf("found at %ld\n", pch - str + 1);
pch = strchr(pch + 1, 's');
}
return 0;
}
char *ft_strchr(const char *s, int c)
{
int i;
i = 0;
while (s[i])
{
if (s[i] == c)
return ((char*)s + i); //const이기 때문에 char포인터로 형변환
//return ((char*)&s[i]); //const이기 때문에 char포인터로 형변환
// char포인터로 형변환을 하지 않으면 인덱싱도 불가하다.
i++;
}
if (s[i] == c) // c가 null일 경우를 위해서
return ((char*)s + i);
return (0);
}
문자열에서 문자를 검색하되 가장 마지막으로 나타나는 위치를 찾는다. (reverse)
#include <string.h> // C++ 에서는 <cstring>
char *strrchr(char *s, int c);
문자열에서 문자를 검색하되 가장 마지막으로 나타나는 위치를 찾는다.
그리고 이를 가리키는 포인터를 리턴한다.
이 때 문자열의 널 종료 문자 역시 C 문자열의 일부분이라 생각한다.
따라서 이 함수는 문자열의 널 종료 문자를 가리키는데 사용될 수 도 있다.
예외처리
```null
if (last[i] == find)
return (last);
```
s가 빈문자열일 때, s의 첫 글자만 c일 때 NULL이 아니라 s의 첫글자를 반환해야 함.
s
: 문자 or 문자열c
: s
에서 찾을 문자 (int
로 전달되지만 함수 내부적으로 다시 char
로 변환되어 처리된다.)s
에서 찾은 문자의 위치를 리턴한다. null
을 리턴한다.#include <stdio.h>
#include <string.h>
int main() {
char str[] = "This is a sample string";
char* pch;
pch = strrchr(str, 's');
printf("Last occurence of 's' found at %ld \n", pch - str + 1);
return 0;
}
char *ft_strrchr(char *s, int c)
{
int i;
i = strlen(s);
while(i >= 0)
{
if (s[i] == (char)c)
return (&s[i]);
i--;
}
return (0);
}
문자열 내에서 부분문자열을 탐색한다.
#include <string.h>
char *strnstr(const char *big, const char *little, size_t len);
big
의 처음부터 len
까지 little
문자열이 포함되었는지 검색한다.null
문자는 포함하지 않는다.big
: 검색할 대상 문자열little
: big
에서 검색할 문자열len
: big
에서 검색할 구간의 길이null
을 리턴한다.little
이 null
이면 big
을 그대로 반환한다.big
의 문자열 길이 혹은 len
보다 little
의 문자열 길이가 더 길면 null
을 반환한다. (찾을 필요도 없이 null이기 때문에 )#include <stdio.h>
#include <string.h>
int main() {
char str[] = "This is a simple string";
char* pch;
pch = strnstr(str, "simple", 16); // 15이하로 설정하면 null출력
printf("pch : %s\n", pch);
return 0;
}
char *ft_strnstr(const char *big, const char *little, size_t len)
{
size_t i;
size_t j;
// 만약 little이 null이면 big을 그대로 반환한다.
if (little[0] == 0)
return ((char *)big);
// 주의!
// if (!little)
// return ((char *)big);
// 이렇게 하면 안된다.
// 입력 값이 null이라는건 입력을 "" 이렇게 한거인데
// null값을 갖고 있는 주소를 갖고 있기 때문에
// little[0] == 0 일때 라고 처리하는게 맞다.
i = 0;
while (big[i] && i < len)
{
j = 0;
while (big[i + j] == little[j] && i + j < len)
{
j++;
if (little[j] == 0)
return ((char *)big + i);
}
i++;
}
return (0);
}
두 문자 열의 일부 문자열을 비교한다.
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
두 문자열의 처음부터 n까지만 정확히 일치하는지 비교한다.
두 문자열의 길이가 n보다 작을때는 처음부터 null까지 일치하는지 비교한다.
일치하면 0
반환, 일치하지 않으면 최초로 불일치 하는 차이값 리턴 (s1[i] - s2[i]
)
#include <stdio.h>
#include <string.h>
int main() {
char str[][5] = {"R2D2", "C3PO", "R2A6"};
int n;
puts("Looking for R2 astromech droids...");
for (n = 0; n < 3; n++)
if (strncmp(str[n], "R2xx", 2) == 0) {
printf("found %s\n", str[n]);
}
return 0;
}
int ft_strncmp(const char *s1, const char *s2, size_t n)
{
size_t i;
i = 0;
while ((i < n) && (s1[i] || s2[i]))
{
if (s1[i] != s2[i])
return (s1[i] - s2[i]);
i++;
}
return (0);
}
문자열을 정수(int)로 변환한다.
#include <stdlib.h>
int atoi(const char *str);
+
나 -
가 올 수 도 있다int
값을 리턴한다.#include <stdio.h>
int main() {
char s[] = "-2147483647";
int num = atoi(s);
printf("res : %d\n", num);
return (0);
}
int ft_atoi(const char *str)
{
size_t i;
int res;
int sign;
res = 0;
sign = 1;
i = 0;
while (str[i] == ' ' || (str[i] >= 9 && str[i] <= 13))
i++;
if (str[i] == '+' || str[i] == '-')
{
sign *= (str[i] == '-') ? -1 : 1;
i++;
}
while (str[i] >= '0' && str[i] <= '9')
{
res = (res * 10) + (str[i] - '0');
i++;
}
return (sign * res);
}
알파벳인지 확인하다.
int isalpha(int c)
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c<= 'Z'))
return (1);
else
return (0);
}
숫자형문자(digit)인지 확인한다.
int ft_isdigit(int c)
{
if (c >= '0' && c <= '9')
return (1);
else
return (0);
}
알파벳이거나 숫자인지 확인한다.
int ft_isalnum(int c)
{
if (ft_isalpha(c) || ft_isdigit(c))
return (1);
else
return (0);
}
아스키코드인지 확인하다
int ft_isascii(int c)
{
if (c >= 0 && c <= 127)
return (1);
else
return (0);
}
출력가능한 문자인지 확인한다.
아스키코드상 32~126 까지만 출력이 가능하다.
int ft_isprint(int c)
{
if (c >= 32 && c <= 126)
return (1);
else
return (0);
}
소문자를 대문자로 바꾼다.
int ft_toupper(int c)
{
if (c >= 'a' && c <= 'z')
return (c - 'a' + 'A');
else
return (c);
}
대문자를 소문자로 바꾼다.
int ft_toupper(int c)
{
if (c >= 'A' && c <= 'Z')
return (c - 'A' + 'a');
else
return (c);
}
/*문자 10개를 저장하기 위한 동적 메모리할당 */
// malloc
char *p = (char *)malloc(sizeof(char)*10);
// calloc
char *p = (char *)calloc(10, sizeof(char));
malloc은 할당된 공간의 값을은 바꾸지 않는다.
calloc은 할당된 공간의 값을 모두 0으로 바꾼다.
배열을 할당하고 모두 0으로 초기화할 필요가 있을경우에는 calloc을 쓰면 편하다.
#include <stdlib.h>
calloc(size_t count, size_t size);
count
는 메모리의 단위 갯수, size
는 메모리 1개당 크기 (ex. 4개 x 4바이트 , 10개 x 1바이트)문자열을 새로운 메모리에 할당하여 복사한다.
#include <stdio.h>
int main()
{
char *line = "hello world!";
char *dupstr = NULL;
dupstr = ft_strdup (line);
printf("%s\n", dupstr);
free(dupstr);
}
#include <stdlib.h>
char *ft_strdup(const char *s)
{
size_t i;
char *res;
res = (char*)malloc(sizeof(char) * (ft_strlen(s) + 1));
if (!res)
return (0);
i = 0;
while (s[i])
{
res[i] = s[i];
i++;
}
res[i] = 0;
return (res);
}
memmove
vs memcpy
memcpy
와이 차이점은 memcpy
는 곧바로 어딘가를 거치지 않고 그 위치에 복사해서 붙여넣는다 생각하면되고memmove
는 훨씬 더 안전하게 복사할 것을 버퍼에 복사하고 해당 위치에 가서 버퍼에 복사 된것을 붙여 넣는 식으로 동작이 구현되어있다.memcpy
와 memmove
는 똑같이 복사하는 기능이지만 memcpy
는 버퍼를 거치지 않아 빠르고, memmove
는 버퍼를 이용하여 안전하다.memcpy
는 서로 메모리 영역이 겹치면 안된다. 만약 두 메모리 블록이 겹쳐저 있다면 memmove()
함수를 사용하자.memcmp
vs strcmp
memcpy
는 두 문자열 중 하나가 끝나더라도(널 값이 나오더라도) 상관없이 서로 다른 값이 나오거나, n개가 될 때 까지 비교를 수행한다.strncmp
는 s1과 s2가 모두 NULL값이 나오면 남은 카운트에 관계없이 0을 반환한다.이 때 초기화 할 값인 c는 인자로는 int로 전달되지만 함수 내부적으로는 unsigned char
로 형변환 되어서 사용된다.
**메모리에 접근할 때에는 signed char형이 아닌 unsigned char형을 사용해야하는 이유**
unsigned char 는 모든 bit를 투명하게 볼 수 있는 특성을 제공합니다.
즉, 다른 type 은 내부 비트의 일부를 값을 표현하기 위한 용도가 아닌 다른 용도(부호 비트)로 사용할 수 있으나 unsigned char 는 이것이 허락되지 않습니다.
따라서, 임의의 메모리에 바이트 단위로 접근해 값을 다룰 때에는 반드시 unsigned char 를 사용해야 full portability 를 얻을 수 있는 것입니다. 또한, 그와 같은 이유로 signed char 가 표현할 수 있는 값의 개수보다 unsigned char 가 표현할 수 있는 값의 개수가 많다는 사실에도 유의할 필요가 있습니다. signed char <-> unsigned char 사이의 값 변환이 1:1 로 이루어질 수 "없는" 경우도 있음을 의미합니다.
이런 이유로, 표준이 바이트 값에 접근해야 하는 경우나 문자에 접근해야 하는 경우 (예: mem(), str() 함수들) 에는 모두 unsigned char 로 접근하도록 요구하고 있습니다.
출처 : https://kldp.org/node/75686
바이트 단위로 초기화 하기 때문에 int형 배열을 초기화 할 때는 주의해야 한다.
예를 들면 ft_memset(arr, 1, sizeof(arr))을 호출하면 arr 배열이 모두 1로 초기화 된다고 생각하는데, 실제로는 배열이 모두 `16843009`로 초기화 된다. 16843009의 2진수 표현은 `0001 00000001 00000001 00000001` 이다. 즉, arr 배열은 1바이트(8비트)당 1로 초기화 된 것이다. *바이트가 딱 떨어지게 초기화 되지 않기 때문에 int형 배열의 요소를 1로 초기화 할 수 없다.* 다른 정수도 모두 마찬가지다. 딱 4개의 값만 가능하다고 한다. `0`, `-1`, `0x3f`, `0x7f`.
출처 : https://blog.naver.com/chogahui05/221484049429