ft_lstmap 구현

yeonjkim·2021년 5월 23일
0

42seoul-libft

목록 보기
16/43

1. ft_lstmap 용도

* 파라미터로 받은 연결 리스트의 각 content에 f 함수를 적용한 새 연결 리스트를 만드는 함수
* 새 노드를 malloc하는 데 실패할 경우 새롭게 만든 모든 lst의 content와 lst를 free해 줌

2. 연결 리스트(linked list)분석

  • 연결 리스트는 배열과 같은 선형 자료구조로, 하단의 사진과 같이 노드들이 메모리 상에 연속적으로 저장되어 있지 않고 포인터로 연결되어 있는 리스트이다.

  • 링크드 리스트의 제일 첫 노드를 가리키는 포인터가 있다.(하단의 사진에서는 head 변수)

  • 각 노드들은 value를 저장하는 data 변수와 다음 노드의 주소값을 저장하는 포인터 변수 next로 구성된다.

3. *lst == NULL과 lst == NULL의 차이

  • lst가 NULL이면 리스트 자체가 존재하지 않는다는 뜻이다.

  • *lst는 lst의 첫번째 주소, head를 의미하므로 리스트 내에 노드가 존재하지 않는다는 뜻이다.

4. t_list와 ft_lstmap()

  • ft_lstmap 함수에서는 t_list 구조체의 인스턴스가 노드이며, t_list 구조체는 아래와 같다.
typedef struct          s_list
{
        void                    *content;
        struct s_list   *next;

}                                       t_list;
  • 또, ft_lstmap 함수에서 t_list 포인터는 lst이며, lst의 content를 삭제하는 함수 포인터가 del(), lst의 content에 적용할 함수 포인터가 f()이다. 즉, lst는 t_list 포인터이며 lst의 content를 제거하기 위해 del함수를 이용, 새로 만들 리스트의 content를 얻기 위해 f함수를 이용해야 한다.

5. ft_lstmap 프로토타입

void	ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
  • t_list *lst : t_list 포인터
  • void *(*f)(void *) : lst의 content에 적용할 함수 포인터
    
  • void *(del)(void *) : lst의 content를 free하기 위한 함수 포인터

6. 구현 시 유의사항

  • lst가 NULL이면 리스트가 비어 있다는 뜻. lst의 content를 이용해야 하나 lst가 비어 있으므로 NULL을 리턴해 주면 됨. 이 부분은 따로 구현하지 않았고, lst가 NULL이면 while문을 돌지 않고 node가 NULL인 채로 리턴됨.

  • lst의 content로 새 노드 newnode를 만들 때 이미 구현한 ft_lstnew() 이용. ft_lstnew 함수는 libft의 ft_lstnew 구현 포스팅 참고.

  • 새 노드를 할당하는 데 실패했을 경우엔 지금까지 만든 새로운 리스트의 content와 리스트 모두 free해줌. 이 때에는 ft_lstclear() 이용. ft_lstclear 함수는 libftdml ft_lstclear 구현 포스팅 참고.

  • 하단의 구현 부분을 보면, 나는 t_list 포인터 newnode를 이용해 새 노드를 만든 후 ft_lstadd_back()을 통해 만든 새로운 리스트 node의 마지막 부분에 계속 newnode를 넣었다. 그러나 이 함수가 종료될 때 node와 newnode 모두 값이 존재하는데, 실제로 이 함수에서 값이 필요한 것은 리턴되는 node이다. 그래서 newnode에 NULL을 채운 후 리턴하였다. 이렇게 newnode에 널을 채우지 않고 리턴하면 다른 테스트기에선 ok가 뜨지만 한 테스트기에서 fail이 뜬 것을 확인할 수 있었다.

7. 코드 구현

#include "libft.h"

t_list          *ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
{
        t_list  *newnode;
        t_list  *node;

        node = NULL;
        while (lst)
        {
                newnode = ft_lstnew(f(lst->content));
                if (!newnode)
                {
                        ft_lstclear(&node, del);
                        return ((void*)(0));
                }
                ft_lstadd_back(&node, newnode);
                lst = lst->next;
        }
        newnode = NULL;
        return (node);
}

8. 코드 구현 방법

(1) 새 노드를 만드는 데 필요한 t_list 포인터 newnode와 새 리스트의 첫번째 노드인 t_list 포인터 node를 선언.
(2) node를 NULL로 초기화한 후 lst가 NULL이 아닐 때까지 while을 돌림.
(3) ft_lstnew()를 통해 lst의 content에 f함수를 적용한 값을 content로 하는 새 노드를 할당.
(4) newnode 할당에 실패하면 현재까지 만든 새 리스트와 리스트의 content를 free해야 하므로 ft_lstclear() 이용한 뒤 0리턴.
(5) node의 맨 뒤에 newnode를 넣은 후 lst가 lst의 next를 가리키게 함.
(6) 더 이상 필요치 않은 newnode에 NULL을 저장한 후 node 리턴.

0개의 댓글