lstadd_front?

typedef struct s_list
{
	void			*content;
	struct s_list	*next;
}	t_list;
//원 함수 없음
    void ft_lstadd_front(t_list **lst, t_list *new);

구현해야할 함수 기능

: Adds the element ’new’ at the beginning of the list.

해석 및 부연설명

: 원소 ‘new’를 리스트의 맨 앞에 추가한다. 이 때 첫번째 매개변수는 리스트 맨 앞에 위치한 원소의 주소를 나타내는 포인터이고, 두번째 매개변수는 리스트에 추가할 원소이다.

ex)

t_list	*start;
t_list	*list1;
t_list	*list2;
t_list	*list3;

list1 = ft_lstnew("abcde");
list2 = ft_lstnew("12345");
list3 = ft_lstnew("!@#$");

ft_lstadd_front(&start, list3);
printf("%s\n", (char *)start->content);
ft_lstadd_front(&start, list2);
printf("%s\n", (char *)start->content);
ft_lstadd_front(&start, list1);
printf("%s\n", (char *)start->content);

코드 실행 결과

!@#$
12345
abcde

리스트의 시작 노드인 start에 정상적으로 노드들이 추가되었다.

의문점 및 생각해볼점

  1. 연결 리스트의 구조
  2. 왜 이중포인터?

노드 삽입 / 추가 / 삭제

자세한 설명과 영상 링크
head 노드(데이터가 저장되어있지 않은 단순한 첫번째 노드)를 *lst[0]이라고 보면 링크의 내용을 그대로 적용시킬 수 있다.
결국 연결 리스트는 선형적으로 이루어져있으니 앞 뒤 연결을 어떻게 잘 하느냐가 중요한 듯 하다.


매개변수로 이중 포인터를 받는 이유

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

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

위 두 경우에는 기능상의 차이가 있을까?
물론 차이가 있기에 던진 질문이다.

  • 매개변수를 이중 포인터로 사용할 경우, 마지막에 맨 처음 노드를 new로 지정해주는 *lst = new부분이 정상적으로 작동한다. 이중포인터(**lst) 변수의 주소값 내부에 저장된 값(*lst라는 포인터 변수의 값)을 바꾼 것이기 때문이다.
  • 매개변수를 그냥 포인터로 사용할 경우, lst = new는 매개변수로 받아온 포인터 변수의 값을 바꾸는 것이 되어버린다. 이때 포인터 변수의 값은 해당 함수 안에서의 지역변수 취급이 되어 함수 안에서만 바뀔 뿐이다.
    관련 내용을 한번 다룬적이 있다. 다만 본 내용을 동료평가때 새롭게 깨닫게 된 터라 순서는 좀 뒤죽박죽이다.
    링크

ft_lstadd_front 구현

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

이중 포인터 **lst는 리스트의 첫번째 노드가 저장되어있는 포인터의 주소가 저장되어있다. 따라서 *lst는 첫번째 노드의 주소를 가리키며, new->next를 *lst로 지정해줌으로써 새로 추가할 new가 *lst 앞에 위치하도록 한다.
다만 이렇게 끝낼경우 리스트의 시작지점은 여전히 *lst로 남아있기 때문에, *lst를 new로 지정하여 new 노드가 리스트의 시작지점을 가리키도록 한다.