
Born to Code
42서울 본과정
금방 할 수 있는 것은 제외했습니다.토글이 없어 보기 힘듭니다.
노션과 깃 페이지를 남겨두니 참고하세요.
#include <string.h>
void *
memset(void *b, int c, size_t len);
구현 코드
void *ft_memset(void *p, int c, size_t len)
{
size_t i;
char *ptr;
i = 0;
ptr = (char *)p;
while (i < len)
{
ptr[i] = (unsigned char)c;
i++;
}
return ((void*)ptr);
}
b 가 가리키는 메모리 주소부터 len 바이트만큼 c값을 채운다.int로 받는 c는 함수 내부에서 unsigned char로 자동 변경된다.unsigned char는 모든 bit를 투명하게 볼 수 있다. (부호비트가 없기 때문)unsigned char를 사용한다.0, -1, 0x3F, 0x7F를 제외한 나머지 값은 원하는 값으로 초기화할 수 없다.성공 시 첫번째 인자로 들어간 ptr을 반환, 실패 시 NULL을 반환한다.
memset()과 bzero() 모두 unsigned char로 캐스팅하는 과정이 있다.0이외의 값으로 초기화 안됨.int n;
memset(&n, 1, sizeof(int));
//n = [00000001000000010000000100000001] = 16843009
struct A
{
int i;
char* c;
};
void main()
{
A a;
a.c = new char[100];
memset(&a, 0, sizeof(A));
if(a.c != NULL)
{
delete[] a.c;
a.c = NULL;
}
}
/*여기서 sizeof(A)는 struct member alignment가 어떤 값이든
4(int i) + 4(char* c, address는 4) = 8Bytes.
그러므로 위의 소스는 동적으로 생성한 변수는 초기화가 되지 못하고,
char* c가 NULL로 초기화가 됨으로써,
이전에 생성한 메모리는 메모리 누수가 발생.*/
//사용 시 분리하여 초기화
a.i = 0;
memset(a.c, 0, sizeof(char)*100);
# 🚀 bzero
---
```c
#include <string.h>
void
bzero(void *s, size_t n);
구현 코드
void ft_bzero(void *p, size_t n)
{
size_t i;
char *ptr;
ptr = (char *)p;
i = 0;
while (i < n)
{
ptr[i] = 0;
i++;
}
return ;
}
s가 가리키는 메모리로부터 n바이트만큼 0값을 채운다.none
memset()과 bzero() 모두 unsigned char로 캐스팅하는 과정이 있다.#include <string.h>
void *
memcpy(void *restrict dst, const void *restrict src, size_t n);
❗42에서 restrict 사용 불가
구현 코드
void *ft_memcpy(void *dest, const void *src, size_t n)
{
char *temp_dest;
const char *temp_src;
size_t i;
i = 0;
temp_dest = (char *)dest;
temp_src = (const char *)src;
while (i < n)
{
temp_dest[i] = temp_src[i];
i++;
}
return (dest);
}
memcpy()함수는 src가 가리키는 메모리 주소로부터 n바이트 크기(길이)만큼 dst메모리에 복사한다.dst를 반환한다.
#include <string.h>
void *
memccpy(void *restrict dst, const void *restrict src, int c, size_t n);
❗42에서 restrict 사용 불가
구현 코드
void *ft_memccpy(void *dst, const void *src, int c, size_t n)
{
unsigned char *temp_dest;
const unsigned char *temp_src;
size_t i;
i = 0;
temp_dest = (unsigned char *)dest;
temp_src = (const unsigned char *)src;
while (i < n)
{
temp_dest[i] = temp_src[i];
if (temp_dest[i] == (unsigned char)c)
return (temp_dest + i + 1);
i++;
}
return (0);
}
memccpy()함수는 src가 가리키는 메모리 주소로부터 n바이트 크기(길이)만큼 dst메모리에 복사한다. 단, 문자 c를 만나게 되면 c까지 복사하고 중단한다.dest에서 c의 다음 위치 (복사가 끝난 다음 메모리주소)를 리턴한다. c를 만나지 않는다면 n만큼 복사하고 NULL을 반환한다.
c를 1바이트 크기가 아닌 자료형을 사용하여 찾을 경우, 문제가 생긴다.#include <stdio.h>
#include <string.h>
int main(void)
{
int word1[20] = { 0, };
int temp[] = {4423, 2, 3, 65281, 4};
int *result
result = memccpy(word1, temp, 65281, sizeof(temp));
if (result == 0)
printf("ss\n");
for (int i = 0; i < 5; i++)
printf("%d ", word1[i]);
printf("\n");
}
/*---출력---*/
5 2 3 1 0
#include <string.h>
void *
memmove(void *dst, const void *src, size_t len);
구현 코드
void *ft_memmove(void *dst, const void *src, size_t len)
{
unsigned char *temp_dest;
const unsigned char *temp_src;
temp_dest = (unsigned char *)dst;
temp_src = (const unsigned char *)src;
if (temp_dest <= temp_src)
while (len--)
*(temp_dest++) = *(temp_src++);
else
{
temp_dest += (len - 1);
temp_src += (len - 1);
while (len--)
*temp_dest-- = *temp_src--;
}
return (dst);
}
len바이트만큼 src 메모리에서 dest로 복사한다.크다면, 순차적으로 데이터를 복사하면 된다.작다면, src 마지막 바이트부터 dest + len에 복사한다.dest 반환.
src 시작주소가 dest 시작 주소보다 앞에 있으면서 두 주소 차이가 len보다 작으면 발생한다.#include <string.h>
void *
memchr(const void *s, int c, size_t n);
구현 코드
void *ft_memchr(const void *p, int c, size_t n)
{
const unsigned char *ptr;
unsigned char value;
ptr = (const unsigned char *)p;
value = (unsigned char)c;
while (n--)
{
if (*ptr == value)
return ((void *)ptr);
ptr++;
}
return (0);
}
s가 가리키는 메모리 주소로부터 n바이트 중 처음으로 c와 일치하는 값의 주소를 리턴한다.c와 일치하는 값의 주소를 리턴한다. 찾지 못하면 NULL을 반환한다.
#include <string.h>
int
memcmp(const void *s1, const void *s2, size_t n);
구현 코드
int ft_memcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char *ptr1;
const unsigned char *ptr2;
ptr1 = (const unsigned char *)s1;
ptr2 = (const unsigned char *)s2;
while (n--)
{
if (*ptr1 != *ptr2)
return (*ptr1 - *ptr2);
ptr1++;
ptr2++;
}
return (0);
}
s1이 가리키는 n바이트만큼의 데이터와 s2가 가리키는 n 바이트만큼의 데이터를 비교하여, 같으면 0을 리턴하고 다르면 0이 아닌 값을 리턴한다.위 기재
#include <string.h>
size_t
strlcpy(char * restrict dst, const char * restrict src, size_t dstsize);
구현 코드
size_t ft_strlcpy(char *dst, char *src, size_t dstsize)
{
size_t i;
i = 0;
while (i + 1 < size && src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
while (src[i] != '\0')
i++;
return (i);
}
dstsize가 0이 아닌 경우 dstsize - 1만큼 문자를 src에서 dst로 복사 후 null을 포함하여 종료한다.#include <string.h>
char *ft_strchr(const char *s, int c);
구현 코드
char *ft_strchr(const char *s, int c)
{
while (*s)
{
if (*s == (char)value)
return (s);
s++;
}
return (0);
}
c의 주소를 리턴한다. 찾는 문자가 s안에 없다면 NULL포인터를 리턴한다.
#include <string.h>
char *
strnstr(const char *haystack, const char *needle, size_t len);
구현 코드
needle이 처음 나타나는 주소를 리턴한다. 만약 없다면 NULL을 리턴한다.
구현 코드
int ft_atoi(const char *str)
{
unsigned long long answer;
unsigned long long max;
int flag;
answer = 0;
flag = 1;
max = 9223372036854775807;
while ((*str >= 9 && *str <= 13) || *str == ' ')
str++;
if (*str == '+' || *str == '-')
{
if (*str == '-')
flag *= -1;
str++;
}
while (ft_isdigit(*str))
{
answer = (answer * 10) + (*str - '0');
if (flag == 1 && answer > max)
return (-1);
if (flag == -1 && answer > max + 1)
return (0);
str++;
}
return (answer * flag);
}
long long max 보다 큰 오버플로우 시 -1, long long min 보다 작은 언더플로우 시 0이 반환된다.#include <stdlib.h>
void *
calloc(size_t count, size_t size);
구현 코드
void *ft_calloc(size_t count, size_t size)
{
void *ptr;
ptr = malloc(count + size);
if (!ptr)
return (0);
ft_bzero(ptr, count * size);
return (ptr);
}
size크기(바이트)의 count개수만큼 바이트를 할당한다.0으로 초기화한다.할당된 메모리 주소를 반환한다.
#include <string.h>
void *ft_calloc(size_t count, size_t size)
구현 코드
void *ft_calloc(size_t count, size_t size)
{
void *ptr;
ptr = malloc(count + size);
if (!ptr)
return (0);
ft_bzero(ptr, count * size);
return (ptr);
}
s1이 복사되어 충분히 들어갈만한 공간을 확보하고, 문자열을 복사한다.str길이 + 1 만큼 확보되어야 한다.복사된 문자열의 주소를 반환한다. 에러 발생시 NULL을 반환한다.
char *ft_substr(char const *s, unsigned int start, size_t len)
구현 코드
char *ft_substr(char const *s, unsigned int start, size_t len)
{
char *ptr;
size_t l;
if (!s)
return (0);
if (ft_strlen(s) < start)
return (ft_strdup(""));
if (len > ft_strlen(s))
l = ft_strlen(s);
else
l = len;
ptr = (char *)malloc(sizeof(char) * (l + 1));
if (!ptr)
return (0);
if (l == 0)
ptr[0] = 0;
else
ft_strlcpy(ptr, (char *)(s + start), l + 1);
return (ptr);
}
s.start and is of maximum size len하위문자열을 반환한다.
문자열의 길이보다 start 값이 클 경우 빈 문자열을 반환한다.
복사할 문자열의 길이가 len보다 짧으면 그만큼만 복사 후 반환한다. (문자열 할당 길이는 변동 x)
char *ft_strjoin(char const *s1, char const *s2)
구현 코드
char *ft_strjoin(char const *s1, char const *s2)
{
size_t s1_len;
size_t s2_len;
char *ptr;
if (!s1 && !s2)
return (0);
if (!s1)
return (ft_strdup(s2));
else if (!s2)
return (ft_strdup(s1));
s1_len = ft_strlen(s1);
s2_len = ft_strlen(s2);
if (!(ptr = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1))))
return (0);
ft_memcpy(ptr, s1, s1_len);
ft_strlcpy(ptr + s1_len, (char *)s2, s2_len + 1);
return (ptr);
}
s1과 s2를 연결한 새로운 문자열을 반환한다.
전부 널이면 0을 반환한다.하나만 널일경우 나머지 문자열만 복제하여 반환한다.char *ft_strtrim(char const *s1, char const *set)
구현 코드
char *ft_strtrim(char const *s1, char const *set)
{
char *start_ptr;
char *end_ptr;
char *answer;
if (!s1)
return (0);
if (!set)
return (ft_strdup(s1));
start_ptr = (char *)s1;
while (*start_ptr && ft_strchr(set, *start_ptr))
start_ptr++;
if (!(*start_ptr))
return (ft_strdup(""));
end_ptr = (char *)s1;
while (*end_ptr)
end_ptr++;
end_ptr--;
while (start_ptr < end_ptr && ft_strchr(set, *end_ptr))
end_ptr--;
if (start_ptr >= end_ptr)
return (ft_strdup(""));
if (!(answer = (char *)malloc((end_ptr - start_ptr + 1) + 1)))
return (0);
ft_strlcpy(answer, start_ptr, (end_ptr - start_ptr + 1) + 1);
return (answer);
}
set에 지정된 문자들을 제거한 문자열을 새로 복제하여 반환한다.위 참고
0을 반환한다.s1을 복제하여 반환한다.char **ft_split(char const *s, char c)
구현 코드
static size_t get_strs_size(char const *s, char c)
{
size_t size;
int flag;
size = 1;
flag = 0;
while (*s)
{
if (*s != c)
break ;
s++;
}
while (*s)
{
if (*s == c)
{
if (*(s + 1) != c && *(s + 1) != 0)
size++;
}
s++;
}
return (size);
}
static void set_all_memory_null(char **strs, size_t index)
{
size_t i;
i = 0;
while (i < index)
free(strs[i++]);
free(strs);
return ;
}
char **ft_split(char const *s, char c)
{
char **strs;
char *patrol;
size_t index;
index = 0;
if (!(strs = (char **)malloc(sizeof(char *) * (get_strs_size(s, c) + 1))))
return (0);
while (*s)
if (*s != c)
{
patrol = (char *)s;
while (*patrol && *patrol != c)
patrol++;
if (!(strs[index] = (char *)malloc(patrol - s + 1)))
{
set_all_memory_null(strs, index - 1);
return (0);
}
ft_strlcpy(strs[index++], (char *)s, patrol - s + 1);
s = patrol;
}
else
s++;
strs[index] = 0;
return (strs);
}
이차원 배열에 저장하여 반환한다. 이때 배열은 null로 끝나야 한다.맨 끝에 null이 들어간 이차원 배열.
문자열이 나열된 배열이라 생각하자.char *ft_itoa(int n)
구현 코드
static int get_number_digits(int n)
{
int answer;
answer = 0;
if (n <= 0)
answer++;
while (n)
{
answer++;
n = n / 10;
}
return (answer);
}
static int get_abs_num(int num)
{
if (num < 0)
return (num * -1);
return (num);
}
char *ft_itoa(int n)
{
int len;
int minus_flag;
char *result;
minus_flag = 1;
if (n < 0)
minus_flag *= -1;
len = get_number_digits(n);
if (!(result = (char *)malloc(len + 1)))
return (0);
result[len--] = 0;
while (len >= 0)
{
result[len] = get_abs_num(n % 10) + '0';
n = n / 10;
len--;
}
if (minus_flag == -1)
result[0] = '-';
return (result);
}
문자열
char *ft_strmapi(char const *s, char (*f)(unsigned int, char))
구현 코드
char *ft_strmapi(char const *s, char (*f)(unsigned int, char))
{
char *result;
size_t len;
size_t i;
if (!s || !f)
return (0);
len = ft_strlen(s);
i = 0;
if (!(result = (char *)malloc(sizeof(char) * len + 1)))
return (0);
while (s[i])
{
result[i] = f(i, s[i]);
i++;
}
result[i] = 0;
return (result);
}
s[0] ⇒ t[f(s[0])]복제된 문자열
함수포인터에 대해 알아보자.void ft_putchar_fd(char c, int fd)
구현 코드
void ft_putchar_fd(char c, int fd)
{
if (fd < 0)
return ;
write(fd, &c, 1);
}
void ft_putstr_fd(char *s, int fd)
구현 코드
void ft_putstr_fd(char *s, int fd)
{
if (!s || fd < 0)
return ;
write(fd, s, ft_strlen(s));
}
void ft_putendl_fd(char *s, int fd)
구현 코드
void ft_putendl_fd(char *s, int fd)
{
if (!s || fd < 0)
return ;
ft_putstr_fd(s, fd);
write(fd, "\n", 1);
}
void ft_putnbr_fd(int n, int fd)
구현 코드
static void print_number(unsigned int num, int fd)
{
char c;
if (num <= 0)
return ;
print_number(num / 10, fd);
c = num % 10 + '0';
write(fd, &c, 1);
}
void ft_putnbr_fd(int n, int fd)
{
unsigned int num;
if (fd < 0)
return ;
if (n < 0)
write(fd, "-", 1);
else if (n == 0)
{
write(fd, "0", 1);
return ;
}
if (n == -2147483648)
num = 2147483648;
else
{
if (n < 0)
n *= -1;
num = (unsigned int)n;
}
print_number(num, fd);
}
아래 코드부터는 구조체를 사용한 함수들이다.
typedef struct s_list
{
void *content;
struct s_list *next;
} t_list;
t_list *ft_lstnew(void *content)
구현 코드
t_list *ft_lstnew(void *content)
{
t_list *new;
if (!(new = (t_list *)malloc(sizeof(t_list))))
return (0);
new->content = content;
new->next = 0;
return (new);
}
content는 매개변수로 받은 content, next는 널로 초기화하여 반환한다.새 노드
void ft_lstadd_front(t_list **lst, t_list *new)
구현 코드
void ft_lstadd_front(t_list **lst, t_list *new)
{
if (!lst || !new)
return ;
new->next = *lst;
*lst = new;
}
new노드를 추가한다.int ft_lstsize(t_list *lst)
구현 코드
int ft_lstsize(t_list *lst)
{
size_t len;
len = 0;
while (lst)
{
lst = lst->next;
len++;
}
return (len);
}
노드 수를 반환한다.노드의 개수
t_list *ft_lstlast(t_list *lst)
구현 코드
t_list *ft_lstlast(t_list *lst)
{
if (!lst)
return (0);
while (lst->next)
lst = lst->next;
return (lst);
}
마지막 노드를 반환한다.마지막 노드
void ft_lstadd_back(t_list **lst, t_list *new)
구현 코드
void ft_lstadd_back(t_list **lst, t_list *new)
{
t_list *temp;
if (!lst || !new)
return ;
if (!(*lst))
*lst = new;
else
{
temp = ft_lstlast(*lst);
temp->next = new;
}
}
new노드를 추가합니다.void ft_lstdelone(t_list *lst, void (*del)(void *))
구현 코드
void ft_lstdelone(t_list *lst, void (*del)(void *))
{
if (!lst || !del)
return ;
del(lst->content);
free(lst);
}
del함수를 사용하여 노드의 콘텐츠 메모리를 해제하고, 노드를 free한다. next의 메모리를 free해서는 안된다.콘텐츠에 관한 free는 고려하지 않는다.void ft_lstclear(t_list **lst, void (*del)(void *))
구현 코드
void ft_lstclear(t_list **lst, void (*del)(void *))
{
t_list *now;
t_list *next;
now = *lst;
while (now)
{
next = now->next;
ft_lstdelone(now, del);
now = next;
}
*lst = 0;
}
전부 삭제(free)해야한다.컨텐츠 또한 삭제(free)되어야 한다.void ft_lstiter(t_list *lst, void (*f)(void *))
구현 코드
void ft_lstiter(t_list *lst, void (*f)(void *))
{
if (!lst || !f)
return ;
while (lst)
{
f(lst->content);
lst = lst->next;
}
}
f함수를 호출한다.t_list *ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
구현 코드
t_list *ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
{
t_list *result;
t_list *temp_result;
if (!(result = ft_lstnew(f(lst->content))))
return (0);
temp_result = result;
lst = lst->next;
while (lst)
{
if (!(temp_result->next = ft_lstnew(f(lst->content))))
{
ft_lstclear(&result, del);
return (0);
}
temp_result = temp_result->next;
lst = lst->next;
}
return (result);
}
content는 f함수의 반환값으로, 매개변수는 복제할 리스트의 content를 사용한다.