Get_next_line

coh·2022년 8월 2일
0

42seoul

목록 보기
2/3

https://github.com/cheol5/코의 깃허브!

get next line을 구현하는 것이 이번 과제의 목표!

구상

read 함수로 buffer size만큼 읽어올 텐데
이때 개행이 포함되어있는지를 검사한다.

-개행이 포함되지 않았다면 static variable에 strjoin으로 개행이 포함 될 때까지 이어붙인다.
개행이 포함되었다면 더이상 읽지 않는다. (한 줄을 찾았으니까!)

그 후에는 적절히 가공하여 개행을 기준으로 반환할 한줄을 만들고
개행 이후의 글자들은 적절히 다시 malloc해서 static variable에 할당한다.
(이러면 다음 함수 호출할 때 할당된 변수의 데이터는 프로그램 종료될 때까지 남아있게 된다.)

그 후 만든 한 줄을 return하면 gnl이 완성된다.

이 때 주의해야하는 것들이 바로 memory leak 이다. leak이 엄청 나는데 첨에 테스터기 잘못 가져온줄 알았다.
적절히 사용 후 free를 해주는 것이 중요하다. 이 leak은 사실 요즘 system 들은 프로그램이 종료되면 누수도 사라지는데
이 누수가 사라지지 않는 시스템이 있다고 함. 이런 경우 적절히 free를 해주는 것은 매우 중요하다.

부딪힌 error들.

  1. heap use after free에러

대략적으로 free한 포인터를 이용해서 다시 heap memory를 접근중인가보다.. 어디인지 찾아봐야함!
line에 담은 temp 를 free해주고 str에 접근 중이어서 생긴 에러임.
댕글링 포인터와도 연관이 있어보인다.

  1. SIGSEGV에러

Bus Error(SIGBUS) : 참조하려는 메모리 주소가 정상적인 주소가 아닐 때
Segmentation fault(SIGSEGV) : 할당된 메모리 범위 밖을 참조하거나 ROM을 참조하려고 할 때 (read only memory)
Abort :

풀면서 해결해야 했던 점들.

  1. 무한 루프 해결하기 -> 만약 읽는 줄에 개행이 포함되지 않았다면 nbyte는 결국 0으로 될 것이다.
    nbyte = 0 인 것을 이용해서 이런 경우 static variable인 temp를 free 시켜주고 temp = 0으로 초기화를 진행해주었다. 그럼 다음 호출 때
    temp가 0이고 읽을 바이트도 없으므로 temp = 0을 반환하도록 함수를 짰고 그 경우 return (0)을 하도록 했다.

  2. free()의 적당한 장소들 사용 후에는 적절히 free

  3. libft의 함수들을 적절히 수정해야 했다.
    strchr같은 경우 temp의 초기값이 0이므로 NULL포인터가 처음 들어오는 경우 무조건 loop를 한번 돌려주기위해 return (0)을 해주도록 수정했다.
    strdup의 경우 strchr의 주소값과 static variable을 argument로 받게 만들어서 적절히 사용후 free()할 수 있도록 수정했다.
    strjoin의 경우도 이어붙일 대상 문자열이 NULL일 경우 malloc(1)을 해서 '\0'을 집어넣도록 수정했다.
    one_line이라는 한 줄을 가공하는 함수를 만들었고
    find_nl(new line)이라는 \n, 개행문자를 찾는 함수를 만들었다.

4.Timeout
while (변수 < ft_strlen())
이런 식으로 libft를 구현했었는데 여기서 while문 안에서 비교를 할 때 매번 strlen을 호출하면서 비용이 많이 든 것이었다.
따로 변수로 빼줘서 해결.

풀면서 느낀 점들

풀면서 libft함수의 원본들을 많이 수정했는데 이렇게 되니 함수 자체의 독립성이 너무 떨어졌다. 하나의 함수를 변경시키면 다른 함수들이 거미줄처럼 얽혀서 영향을 받게 되어서 유지보수하는데 너무 힘들었다. strdup같은 경우도 원래 아는 함수의 기능보다 추가된 기능이 많아서 다음부터 코드를 짤 때 이런 점들을 고려해서 구현을 해야겠다는 생각이 들었다. (예를 들어 strjoin의 이어붙일 문자열이 null인 경우 원래는 strdup("")를 썼는데 원본함수를 고치다 보니 이런 부분들도 같이 수정을 해야만 했음.)

깃허브에 main문과 code들을 올려놨음.

bonus는 구현하지 않았지만 다른 사람들 말 들어보니 연결리스트로 푼다고 하는데 음..
대충 어떻게 푸는지는 알 것 같음.

구상은 똑같음. 다만 그것을 무엇으로 하냐의 차이인 듯.
한 줄을 읽을 건데 개행이 없으면 나올 때까지 이어 붙임.
개행이 있으면 개행 기준으로 앞 연결리스트 삭제하고 새로운 연결리스트를 static variable이 가리키도록 함.

기타 개념들

read 함수

#include <unistd.h>
ssize_t read (int fd, void *buf, size_t nbytes)

해당 파일을 nbyte만큼 읽어서 buf에 쓴다.
성공 시 읽은 byte수 반환.
실패 시 -1 반환.
EOF에서 읽으려고 한다면 0 반환.

buffer

file은 disk에 있고 buffer는 memory에 있다.
disk에 있는 것을 읽을 때 임시 저장할 공간으로 buffer를 활용하고
이때 만약 정적 배열이나 동적 배열을 이용할 수 있는데
정적배열같은 경우 할당할 수 있는 배열의 크기가 제한되어 buffer size가 큰 경우 segfault가 날 수 있다. 따라서 동적할당을 해야함. 근데 동적 할당도 사실 malloc을 이용하는 건데 size_t의 범위보다 커지면 정상적인 동작을 하지 못함.

read 함수와 offset

gnl보고 가장 처음 고민한 것은 함수를 재호출할 때 읽은 위치부터 다시 읽는 것인지 아니면 파일의 처음부터 다시 읽는 것인지를 고민하는 것이었음.
다행히도 read 함수를 호출하면 file table에서 해당 파일의 offset을 증가시킨 것을 저장해서 읽었던 위치부터 열 수 있었다.

변수의 종류

정적변수, 지역변수, 전역변수

변수의 수명에 대해서 이야기 하면은 정적 변수와 전역변수는 프로그램 종료 시까지 지역변수는 함수의 블록이 종료될 때까지이다. 따라서 gnl을 호출한 프로그램이 종료되지 않는 다면 정적변수는 계속 살아있는 상태로 우리가 원하는 데이터를 저장시킬 수 있다!

profile
Written by coh

0개의 댓글