Libft (2)

folder_open 42Seoul / 42cursus | date_range / created at

sell #42seoul #42서울 #born2code #42cursus #Libft #C #C언어

이전 글

Libft - (1)

Bonus part

Mandatory part를 완벽히 끝내면 Bonus part를 진행할 수 있다. 링크드 리스트를 구현해보자.
설명에 보면 다음과 같이 나와있다.

typedef struct s_list
{
	void *content;
	struct s_list *next;
} t_list;
  • content: 노드 안에 포함된 데이터. 아무 종류의 데이터를 가지고 있는 것이 허용된다.
  • next: 다음 노드의 주소. 마지막 노드이면 NULL이다.

링크드 리스트도 구현해놓으면 앞으로 쓸 일이 많으니 이왕이면 진행하는 것을 추천한다.

이제 구현해야할 함수들로 가보자.

ft_lstnew

새로운 노드를 생성한다. 주어진 content로 초기화하며, 다음 노드는 NULL로 초기화한다.

ft_lstnew.c

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

	arr = (t_list *)malloc(sizeof(t_list));
	if (!arr)
		return (0);
	arr->content = content;
	arr->next = 0;
	return (arr);
}

ft_lstadd_front

주어진 리스트의 맨 앞에 새로운 노드를 추가한다.

ft_lstadd_front.c

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

ft_lstsize

주어진 리스트의 사이즈를 반환한다.

ft_lstsize.c

int	ft_lstsize(t_list *lst)
{
	int	i;

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

ft_lstlast

주어진 리스트의 마지막 노드를 반환한다.

ft_lstlast.c

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

ft_lstadd_back

주어진 리스트의 마지막에 새로운 노드를 추가한다.

ft_lstadd_back.c

void	ft_lstadd_back(t_list **lst, t_list *new)
{
	if (!*lst)
		*lst = new;
	else
		ft_lstlast(*lst)->next = new;
}

ft_lstdelone

주어진 노드를 삭제(해제)시킨다. 단, 다음 노드는 삭제되어서는 안된다.

ft_lstdelone.c

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

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

ft_lstclear

주어진 리스트를 지운다. 즉, 모든 노드들을 삭제한다.

ft_lstclear.c

void	ft_lstclear(t_list **lst, void (*del)(void *))
{
	t_list	*temp;

	while (*lst)
	{
		temp = *lst;
		del((*lst)->content);
		*lst = (*lst)->next;
		free(temp);
	}
}

ft_lstiter

각 노드의 content마다 주어진 함수를 적용시킨다.

ft_lstiter.c

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

ft_lstmap

각 노드의 content마다 주어진 함수를 적용시키는데, 새로운 리스트를 만들어 반환한다.

ft_lstmap.c

static void	*to_free(t_list *first, void *mem, void (*del)(void *))
{
	del(mem);
	if (first)
		ft_lstclear(&first, del);
	return (0);
}

t_list	*ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
{
	t_list	*new_lst;
	t_list	*first;
	void	*ptr;

	if (!lst || !del || !f)
		return (0);
	ptr = f(lst->content);
	new_lst = ft_lstnew(ptr);
	if (!new_lst)
		return (to_free(new_lst, ptr, del));
	first = new_lst;
	lst = lst->next;
	while (lst)
	{
		ptr = f(lst->content);
		new_lst->next = ft_lstnew(ptr);
		if (!(new_lst->next))
			return (to_free(first, ptr, del));
		lst = lst->next;
		new_lst = new_lst->next;
	}
	return (first);
}

아직도 기억나는 게 ft_lstnew(ptr) 해주는 부분에서 처음에는 ft_lstnew(f(lst -> content))와 같이 한 번에 넣었다가,
계속 paco를 통과 못했었던 기억이 있다. 알고 보니 함수 포인터로 들어오는 함수가 실패했을 시에 content를
free해줄 방법이 없어서 터지는 거였다. slack을 한참 뒤지다 알게 되었는데 libft에서 꽤나 유명한 문제였던 것으로 기억한다.

2. 마무리 하며..

어찌저찌 libft에 대한 정리를 끝냈다. 사실 정리라기보다는 감상평 같은 느낌으로다가 한 줄 끄적이곤 한 거 같은데, 이 당시에
분명히 디테일한 생각들이 있었는데 기억이 안나서 조금 아쉬웠다. 여튼 이 글을 보는 사람도 코드 복붙하려하지 말고
한 번쯤 고민해보고 직접 짜는 것을 추천한다. 어차피 나중에 과제하면서 본인이 만들었던 libft를 조금씩 수정해야하니..