[42] Libft 구현하기

KURTY·2022년 8월 29일
0

42_SEOUL

목록 보기
1/9

ft_isalpha

#include "libft.h"

int	ft_isalpha(int c)
{
	return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}

a~z, A~Z 라면 return 1, 아니라면 return 0

ft_isdigit

#include "libft.h"

int	ft_isdigit(int c)
{
	return (c >= '0' && c <= '9');
}

0~9라면 return 1, 아니라면 return 0

ft_isalnum

#include "libft.h"

int	ft_isalnum(int c)
{
	return (ft_isdigit(c) || ft_isalpha(c));
}

if (isdigit && isalpha) return 1

ft_isascii

#include "libft.h"

int	ft_isascii(int c)
{
	return (c >= 0 && c <= 127);
}

ascii값 이내라면 return 1

ft_isprint

#include "libft.h"

int	ft_isprint(int c)
{
	return (c >= 32 && c <= 126);
}

ascii 값 내에서 출력 가능한 값이라면 return 1

ft_strlen

#include "libft.h"

size_t	ft_strlen(const char *s)
{
	size_t	i;

	i = 0;
	while (s[i])
		i++;
	return (i);
}

문자열의 길이 반환함수

ft_memset

#include "libft.h"

void	*ft_memset(void *b, int c, size_t len)
{
	size_t	i;

	i = 0;
	while (i < len)
	{
		((unsigned char *)b)[i] = (unsigned char)c;
		i++;
	}
	return (b);
}

주어지는 길이만큼 주어지는 공간에 주어지는 정수값으로 초기화 하는 함수

memset은 1바이트씩 이동하면서 값을 할당하는 포인터 연산을 해야하는데 usigned char 자료형을 사용하는

이유는 1바이트씩 증가시키기 위해서 char or unsigned char를 사용하는데 일반 char 을 사용하는 경우 음수로 인한 예외를 막기 위해서 usigned char을 사용함

ft_bzero

#include "libft.h"

void	ft_bzero(void *s, size_t n)
{
	ft_memset(s, 0, n);
}

n 만큼 0으로 초기화

ft_memcpy

#include "libft.h"

void	*ft_memcpy(void *dst, const void *src, size_t n)
{
	size_t	i;

	i = 0;
	if (dst == 0 && src == 0)
		return (NULL);
	while (i < n)
	{
		((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
		i++;
	}
	return (dst);
}

메모리의 일부분을 복사함.

strcpy같은 경우는 문자의 값에 따라서 함수가 종료되고, memscpy는 지정한 byte수에 따라서 함수가 종료가 됨

ft_memmove

#include "libft.h"

void	*ft_memmove(void *dst, const void *src, size_t len)
{
	unsigned char	*buf_src;
	unsigned char	*buf_dst;
	size_t			i;

	i = 0;
	buf_src = (unsigned char *)src;
	buf_dst = (unsigned char *)dst;
	if (dst == 0 && src == 0)
		return (NULL);
	while (i < len)
	{
		if (src > dst)
			buf_dst[i] = buf_src[i];
		else
			buf_dst[len - 1 - i] = buf_src[len - 1 - i];
		i++;
	}
	return (buf_dst);
}

메모리 이동 함수

복사할 것을 버퍼에 복사하고, 해당 위치에 가서 버퍼에 복사 된 것을 붙여넣음

메모리를 src에서 dst로 len 바이트 길이 만큼 복사함

memcpy 와 memmove의 차이점은 memcpy는 바로 붙여넣지만 memmove는 버퍼에 저장해놨다가 붙여넣는다. 안정성으로는 memmove가 뛰어나다

ft_strlcpy

#include "libft.h"

size_t	ft_strlcpy(char *dst, const char *src, size_t dstsize)
{
	size_t	srcsize;
	size_t	i;

	srcsize = ft_strlen(src);
	i = 0;
	if (!dst || !src)
		return (0);
	if (dstsize == 0)
		return (srcsize);
	while (src[i] && i + 1 < dstsize)
	{
		dst[i] = src[i];
		i++;
	}
	dst[i] = '\0';
	return (srcsize);
}

src를 dst에 null을 포함해서 (size-1)개 까지 복사 후에 null을 붙여준다.

src의 길이가 size보다 적으면 부족한 부분을 null로 채운다

반환값은 항상 srcsize이다.

ft_strlcat

#include "libft.h"

size_t	ft_strlcat(char *dst, const char *src, size_t dstsize)
{
	size_t	i;
	size_t	dst_len;
	size_t	src_len;

	dst_len = ft_strlen(dst);
	src_len = ft_strlen(src);
	i = 0;
	if (dstsize < dst_len + 1)
		return (dstsize + src_len);
	if (dstsize > dst_len + 1)
	{
		while (src[i] && dst_len + i + 1 < dstsize)
		{
			dst[dst_len + i] = src[i];
			i++;
		}
	}
	dst[dst_len + i] = '\0';
	return (dst_len + src_len);
}

dest의 길이를 포함해서 새로운 dest의 길이를 설정하고 빈 공간 만큼 src를 이어붙인다.

마지막에 null을 보장해서 넣어준다.

dstsize < dst_len + 1인 경우 null공간 + dst_len보다 dstsize가 작음을 의미하므로 기타 작업 수행하지 않고 dstsize+src_len을 반환함

dstsize > dst_len + 1인 경우 기타 작업 수행 후 dstsize+src_len을 반환함

ft_strncmp

#include "libft.h"

int	ft_strncmp(const char *s1, const char *s2, size_t n)
{
	size_t			i;
	unsigned char	*ptr1;
	unsigned char	*ptr2;

	i = 0;
	ptr1 = (unsigned char *)s1;
	ptr2 = (unsigned char *)s2;
	while (i < n)
	{
		if (!ptr1[i] || !ptr2[i] || ptr1[i] != ptr2[i])
			return (ptr1[i] - ptr2[i]);
		i++;
	}
	return (0);
}

문자열 비교 함수

ft_toupper

#include "libft.h"

int	ft_toupper(int c)
{
	return (c - 32 * (c >= 'a' && c <= 'z'));
}

대문자로

ft_tolower

#include "libft.h"

int	ft_tolower(int c)
{
	return (c + 32 * (c >= 'A' && c <= 'Z'));
}

소문자로

ft_strchr

#include "libft.h"

char	*ft_strchr(const char *s, int c)
{
	size_t	i;
	size_t	len;

	i = 0;
	len = ft_strlen(s);
	while (i <= len)
	{
		if (s[i] == (char)c)
			return ((char *)(s + i));
		i++;
	}
	return (NULL);
}

문자열에서 특정한 문자가 가장 먼저 나타나는 곳의 위치를 찾음

ft_strrchr

#include "libft.h"

char	*ft_strrchr(const char *s, int c)
{
	size_t	i;

	i = ft_strlen(s);
	while (s[i] != (char)c && i > 0)
		i--;
	if (s[i] == (char)c)
		return ((char *)(s + i));
	return (NULL);
}

문자열에서 문자를 검색하되 가장 마지막으로 나타나는 위치를 찾음

reverse strchr

ft_memchr

#include "libft.h"

void	*ft_memchr(const void *s, int c, size_t n)
{
	size_t	i;

	i = 0;
	while (i < n)
	{
		if (((unsigned char *)s)[i] == (unsigned char)c)
			return ((void *)(s + i));
		i++;
	}
	return (0);
}

메모리 블록에서 문자를 찾는다

ptr이 가리키는 메모리 처음부터 n바이트까지 탐색하면서 처음으로 value와 일치하는 값의 주소를 리턴한다.

ft_memcmp

#include "libft.h"

int	ft_memcmp(const void *s1, const void *s2, size_t n)
{
	size_t			i;
	unsigned char	*p1;
	unsigned char	*p2;

	if (n == 0)
		return (0);
	i = 0;
	p1 = (unsigned char *)s1;
	p2 = (unsigned char *)s2;
	while (i + 1 < n && p1[i] == p2[i])
		i++;
	return ((p1[i] - p2[i]));
}

두 개의 메모리 블록을 비교한다.

ft_strnstr

#include "libft.h"

char	*ft_strnstr(const char *haystack, const char *needle, size_t len)
{
	size_t	i;
	size_t	j;
	size_t	needle_len;

	i = 0;
	needle_len = ft_strlen(needle);
	if (!*needle)
		return ((char *)haystack);
	while (haystack[i])
	{
		if (haystack[i] == needle[0])
		{
			j = 0;
			while (needle[j] && haystack[i + j] && (i + j) < len)
			{
				if (haystack[i + j] != needle[j])
					break ;
				j++;
			}
			if (j == needle_len)
				return ((char *)haystack + i);
		}
		i++;
	}
	return (NULL);
}

문자열 내에서 부분문자열을 탐색한다.

ft_atoi

#include "libft.h"

int	ft_atoi(const char *str)
{
	int	i;
	int	num;
	int	sign;

	i = 0;
	num = 0;
	sign = 1;
	while (str[i] == ' ' || (str[i] >= 9 && str[i] <= 13))
		i++;
	if (str[i] == '+' || str[i] == '-')
	{
		if (str[i] == '-')
			sign *= -1;
		i++;
	}
	while (str[i] >= '0' && str[i] <= '9')
	{
		num = num * 10 + (str[i] - '0') * sign;
		i++;
	}
	return (num);
}

라피신 코드랑 같음

ft_calloc

#include "libft.h"

void	*ft_calloc(size_t count, size_t size)
{
	void	*ptr;

	if (count <= 0 || size <= 0)
		ptr = (void *)malloc(1);
	else
		ptr = (void *)malloc(count * size);
	if (!ptr)
		return (NULL);
	ft_bzero(ptr, count * size);
	return (ptr);
}

count * size 만큼 malloc하고, 0으로 채움

ft_strdup

#include "libft.h"

char	*ft_strdup(const char *s1)
{
	char	*copy;
	int		len;
	int		i;

	i = 0;
	len = ft_strlen(s1);
	copy = (char *)malloc(sizeof(char) * (len + 1));
	if (!copy)
		return (NULL);
	while (s1[i])
	{
		copy[i] = s1[i];
		i++;
	}
	copy[i] = '\0';
	return (copy);
}

라피신 코드

ft_substr

#include "libft.h"

char	*ft_substr(char const *s, unsigned int start, size_t len)
{
	char	*substr;
	size_t	i;
	size_t	s_len;

	s_len = ft_strlen(s);
	if (len >= s_len)
		len = s_len;
	if (start >= s_len)
		return (ft_strdup(""));
	substr = (char *)malloc(sizeof(char) * (len + 1));
	if (!s || !substr)
		return (NULL);
	i = 0;
	while (i < len && s[start])
		substr[i++] = s[start++];
	substr[i] = '\0';
	return (substr);
}

제공받은 len이 s의 길이보다 길다면 len = ft_strlen(s)

제공받은 start가 s를 넘는다면 “”을 반환함

substr에 s[start]부터의 문자를 집어넣고 ‘\0’을 입력 후 반환

char const vs const char

const char * : 상수형 문자에 대한 포인터, 포인터가 가리키는 변수의 값을 바꿀 수 없음

char const * : 문자에 대한 상수형 포인터, 포인터 값을 바꿀 수 없음

ft_strjoin

#include "libft.h"

char	*ft_strjoin(char const *s1, char const *s2)
{
	char	*new_s;
	size_t	s1_len;
	size_t	s2_len;

	if (!s1 || !s2)
		return (NULL);
	s1_len = ft_strlen(s1);
	s2_len = ft_strlen(s2);
	new_s = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1));
	if (!new_s)
		return (NULL);
	ft_memcpy(new_s, s1, s1_len);
	ft_memcpy(new_s + s1_len, s2, s2_len);
	new_s[s1_len + s2_len] = '\0';
	return (new_s);
}

s1과 s2를 연결한 새로운 문자열을 반환한다.

s1, s2 전부 NULL일 경우 0을 반환한다.

하나만 NULL일 경우 나머지 문자열만 복제하여 반환한다.

ft_strtrim

#include "libft.h"

char	*ft_strtrim(char const *s1, char const *set)
{
	size_t	start;
	size_t	end;
	char	*res;

	if (!s1)
		return (NULL);
	if (!set)
		return ((char *)s1);
	start = 0;;
	while (s1[start] && ft_strchr(set, s1[start]))
		start++;
	end = ft_strlen(s1);
	while (ft_strchr(set, s1[end - 1]) && end > start)
		end--;
	res = ft_substr(s1, start, (end - start));
	return (res);
}

s1이 null이면 0을 반환한다

set이 null이면 s1을 복제하여 반환한다

문자열 전체에 대한 함수가 아니다.

복사된 문자열의 사본을 반환

ft_split

#include "libft.h"

static char	*ft_strndup(char const *s, char c)
{
	size_t	i;
	char	*copy;

	i = 0;
	while (s[i] && s[i] != c)
		i++;
	copy = (char *)malloc(sizeof(char) * (i + 1));
	if (!copy)
		return (NULL);
	i = 0;
	while (s[i] && s[i] != c)
	{
		copy[i] = s[i];
		i++;
	}
	copy[i] = '\0';
	return (copy);
}

static int	count_words(char const *s, char c)
{
	int	i;
	int	nb_word;

	nb_word = 0;
	i = 0;
	while (s[i])
	{
		while (s[i] == c)
			i++;
		if (s[i] && s[i] != c)
		{
			nb_word++;
			while (s[i] && s[i] != c)
				i++;
		}
	}
	return (nb_word);
}

static char	**free_arr(char **s)
{
	int	i;

	i = 0;
	while (s[i])
	{
		free(s[i]);
		i++;
	}
	free(s);
	return (NULL);
}

char	**ft_split(char const *s, char c)
{
	char	**ary;
	int		i;

	i = 0;
	if (!s)
		return (NULL);
	ary = (char **)malloc(sizeof(char *) * (count_words(s, c) + 1));
	if (!ary)
		return (NULL);
	while (*s)
	{
		while (*s && *s == c)
			s++;
		if (*s && *s != c)
		{
			ary[i++] = ft_strndup(s, c);
			if (!ary)
				return (free_arr(ary));
			while (*s && *s != c)
				s++;
		}
	}
	ary[i] = 0;
	return (ary);
}

문자열과 구분자가 주어지면 구분자를 통해서 문자열을 쪼개서 배열로 만들어 반환한다.

ft_itoa

#include "libft.h"

int	count_nbr(long long n)
{
	int	cnt_nbr;

	if (n == 0)
		return (1);
	cnt_nbr = 0;
	if (n < 0)
		cnt_nbr = 1;
	while (n)
	{
		n /= 10;
		cnt_nbr++;
	}
	return (cnt_nbr);
}

char	*ft_itoa(int n)
{
	long long	nbr;
	char		*res;
	int			len;

	len = count_nbr((long long)n);
	nbr = (long long)n;
	if (n < 0)
		nbr *= -1;
	res = (char *)malloc(sizeof(char) * (len + 1));
	if (!res)
		return (NULL);
	res[len--] = '\0';
	while (len >= 0)
	{
		res[len] = nbr % 10 + '0';
		nbr /= 10;
		len--;
	}
	if (n < 0)
		res[0] = '-';
	return (res);
}

정수의 길이를 세어서 문자열로 만들어 반환한다.

뒤에서 부터 붙여넣기 한다.

ft_strmapi

#include "libft.h"

char	*ft_strmapi(char const *s, char (*f)(unsigned int, char))
{
	size_t	len;
	size_t	i;
	char	*str;

	i = 0;
	len = ft_strlen(s);
	str = (char *)malloc(sizeof(char) * (len + 1));
	if (!str)
		return (NULL);
	while (i < len)
	{
		str[i] = f(i, s[i]);
		i++;
	}
	str[i] = '\0';
	return (str);
}

제공받은 문자열 s의 값을 함수에 적용해서 새로운 문자열 str을 만들기

ft_striteri

#include "libft.h"

void	ft_striteri(char *s, void (*f)(unsigned int, char *))
{
	size_t	i;

	i = 0;
	while (*(s + i))
	{
		f(i, s + i);
		i++;
	}
}

제공받은 s라는 문자열을 제공받은 f라는 함수에 적용하면 됨

ft_putchar_fd

#include "libft.h"

void	ft_putchar_fd(char c, int fd)
{
	write(fd, &c, 1);
}

제공받은 fd로 문자 c출력

ft_putstr_fd

#include "libft.h"

void	ft_putstr_fd(char *s, int fd)
{
	int	i;

	i = 0;
	while (s[i])
		write(fd, &s[i++], 1);
}

제공받은 fd로 문자열 s출력

ft_putendl_fd

#include "libft.h"

void	ft_putendl_fd(char *s, int fd)
{
	ft_putstr_fd(s, fd);
	ft_putchar_fd('\n', fd);
}

제공받은 fd로 문자열 s를 출력하고 개행문자 출력

ft_putnbr_fd

#include "libft.h"

void	rec_putnbr(int nb, int fd)
{
	char	c;

	if (nb == 0)
		return ;
	c = '0' + nb % 10;
	rec_putnbr(nb / 10, fd);
	ft_putchar_fd(c, fd);
}

void	ft_putnbr_fd(int n, int fd)
{
	char	c;

	if (n < 0)
	{
		write(fd, "-", 1);
		c = '0' - n % 10;
		rec_putnbr(-(n / 10), fd);
	}
	else
	{
		c = '0' + n % 10;
		rec_putnbr(n / 10, fd);
	}
	ft_putchar_fd(c, fd);
}

제공받은 fd로 정수 출력

ft_lstnew

#include "libft.h"

t_list	*ft_lstnew(void *content)
{
	t_list	*lst;

	lst = (t_list *)malloc(sizeof(t_list));
	lst->content = content;
	lst->next = 0;
	return (lst);
}

새로운 리스트 생성

ft_lstadd_front

#include "libft.h"

void	ft_lstadd_front(t_list **lst, t_list *new)
{
	if (!new)
		return ;
	new->next = *lst;
	*lst = new;
}

리스트의 가장 처음 요소에 제공받은 리스트 추가

ft_lstsize

#include "libft.h"

int	ft_lstsize(t_list *lst)
{
	int	cnt;

	cnt = 0;
	while (lst)
	{
		lst = lst->next;
		cnt++;
	}
	return (cnt);
}

리스트의 크기 반환

ft_lstlast

#include "libft.h"

t_list	*ft_lstlast(t_list *lst)
{
	if (!lst)
		return (lst);
	while (lst->next)
		lst = lst->next;
	return (lst);
}

리스트의 마지막 요소 반환

ft_lstadd_back

#include "libft.h"

void	ft_lstadd_back(t_list **lst, t_list *new)
{
	t_list	*ptr;

	if (!*lst)
	{
		*lst = new;
		return ;
	}
	ptr = *lst;
	while (ptr->next)
		ptr = ptr->next;
	ptr->next = new;
}

리스트의 마지막 요소에 제공받은 리스트 추가

ft_lstdelone

#include "libft.h"

void	ft_lstdelone(t_list *lst, void (*del)(void *))
{
	t_list	*tmp;

	if (!del)
		return ;
	tmp = lst->next;
	del(lst->content);
	free(lst);
	lst = tmp;
}

리스트의 처음 요소 삭제 후 공간 해제

ft_lstclear

#include "libft.h"

void	ft_lstclear(t_list **lst, void (*del)(void *))
{
	t_list	*curr;
	t_list	*next;

	curr = *lst;
	while (curr)
	{
		next = curr->next;
		ft_lstdelone(curr, del);
		curr = next;
	}
	*lst = NULL;
}

모든 리스트의 요소 삭제 후 공간 해제

ft_lstiter

#include "libft.h"

void	ft_lstiter(t_list *lst, void (*f)(void *))
{
	while (lst)
	{
		f(lst->content);
		lst = lst->next;
	}
}

리스트를 순회하며 제공받은 함수를 적용

ft_lstmap

#include "libft.h"

t_list	*ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
{
	t_list	*tmp;
	t_list	*res;

	if (!lst)
		return (NULL);
	res = NULL;
	while (lst)
	{
		tmp = ft_lstnew(f(lst->content));
		if (!tmp)
		{
			ft_lstclear(&lst, del);
			return (NULL);
		}
		ft_lstadd_back(&res, tmp);
		lst = lst->next;
	}
	return (res);
}

임시적인 리스트 tmp와 결과값을 저장할 리스트 res를 선언한다

tmp에 lst의 요소를 함수에 적용한 값을 담는데 실행이 되지 않았다면 lst를 삭제하고 NULL을 반환한다.

성공했다면 res에 붙여넣기 한다.이후 lst를 옮긴다.

Makefile

CC = cc
CFLAGS = -Wall -Wextra -Werror

NAME = libft.a

RM = rm -f

AR = ar
ARFLAGS = crs

INCLUDES = ./libft.h

SRCS_NM = ft_isalpha.c \
		  ft_isdigit.c \
		  ft_isalnum.c \
		  ft_isascii.c \
		  ft_isprint.c \
		  ft_strlen.c \
		  ft_memset.c \
		  ft_bzero.c \
		  ft_memcpy.c \
		  ft_memmove.c \
		  ft_strlcpy.c \
		  ft_strlcat.c \
		  ft_strncmp.c \
		  ft_toupper.c \
		  ft_tolower.c \
		  ft_strchr.c \
		  ft_strrchr.c \
		  ft_memchr.c \
		  ft_memcmp.c \
		  ft_strnstr.c \
		  ft_atoi.c \
		  ft_calloc.c \
		  ft_strdup.c \
		  ft_substr.c \
		  ft_strjoin.c \
		  ft_strtrim.c \
		  ft_split.c \
		  ft_itoa.c \
		  ft_strmapi.c \
		  ft_striteri.c \
		  ft_putchar_fd.c \
		  ft_putstr_fd.c \
		  ft_putendl_fd.c \
		  ft_putnbr_fd.c

SRCS_BN = ft_lstnew.c \
		  ft_lstadd_front.c \
		  ft_lstsize.c \
		  ft_lstlast.c \
		  ft_lstadd_back.c \
		  ft_lstdelone.c \
		  ft_lstclear.c \
		  ft_lstiter.c \
		  ft_lstmap.c

OBJS = $(SRCS_NM:.c=.o)

OBJS_BONUS = $(SRCS_BN:.c=.o)

ifdef WITH_BONUS
		OBJ_FILES = $(OBJS) $(OBJS_BONUS)
	else
		OBJ_FILES = $(OBJS)
endif

all : $(NAME)
	sleep 1

.c.o : $(SRCS)
	$(CC) $(CFLAGS) -c -o $@ $<

$(NAME) : $(OBJ_FILES)
	$(AR) $(ARFLAGS) $@ $^

clean :
	$(RM) $(RMFLAG) $(OBJS) $(OBJS_BONUS)

fclean: clean
	$(RM) $(RMFLAG) $(NAME)

re: fclean all

bonus:
		@make WITH_BONUS=1 all

.PHONY : all clean fclean re bonus

제출할 때는 sleep 1 지우기

profile
진짜 공부하자

0개의 댓글