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
를 사용한다.