100%를 한번에 바꾸는건 어려워도 1%를 100번 바꾸는건 쉽다.

생각정리 자세히보기

42 Seoul

[42 Seoul] Libft

dc-choi 2022. 1. 7. 10:41
반응형

Libft

나만의 첫 번째 라이브러리

 

요약: 이 프로젝트의 목적은 흔히 쓰이는 함수들을 재구성하여 이후의 모든 프로젝트에서 사용될 C 라이브러리를 제작하는 것입니다.

 

알아야할 선수지식

C 문법

const란?

해당 식별자의 값을 변경할 수 없도록 선언한다는 키워드

매개변수에 const를 붙이는 이유?

특정 함수에 전달하는 포인터의 내용이 훼손되는 것을 방지하기 위해서이다. 다른 함수에 포인터가 전달될 경우, call-by-reference 형태로 전달되므로 다른 함수 내에서 포인터의 값을 임의 조작할 수 있기 때문이다.

size_t란?

플랫폼마다 다른 bit의 부호없는 정수형을 사용하기 위해서 사용하는 typedef, 이론상으로 가장 큰 사이즈를 담을 수 있는 unsigned 데이터 타입

 

Introduction

C 프로그래밍을 할 때 매우 유용한 표준 함수들을 사용할 수 없다면 굉장히 지루할 거예요. 이 프로젝트를 통해 이러한 표준 함수들을 구현하고, 이해하고, 어떻게 사용하는 지 배울 수 있습니다. 이 라이브러리는 나중에 진행할 C 프로젝트에도 도움이 될 거에요. 과제를 진행하시면서 여러분의 libft를 확장시켜 보세요. 물론, 어떤 함수가 사용가능한 함수인지 체크하는 것을 잊으시면 안 됩니다!

 

Common Instructions

프로젝트는 Norm 규칙에 맞춰 작성되어야 합니다. 보너스 파일/함수가 존재할 경우, 그 또한 norm 검사에 포함되며 norm error가 있을 시 0점을 받게 됩니다.

 

함수들은 정의되지 않은 행동들과 별개로 예기치 않게 중단되어서는 안 됩니다.(예를 들어, segmentation fault, bus error, double free 등) 만약 이렇게 중단되면, 당신의 프로젝트는 작동하지 않는 것으로 여겨지고 평가에서 0점을 받을 것입니다.

 

필요한 경우 heap에 할당된 모든 메모리 공간은 적절하게 해제되어야 합니다. 메모리 누수는 용납될 수 없습니다.

 

과제에서 필요한 경우, -Wall -Wextra -Werror 플래그를 지정하여 컴파일을 수행하는 Makefile을 제출해야 합니다. Makefile은 relink 되어서는 안 됩니다.

 

Makefile은 최소한 $(NAME), all, clean, fclean, re 규칙을 포함해야 합니다.

 

프로젝트에 보너스를 제출하려면, Makefile에 보너스 규칙을 포함해야 합니다. 이 보너스 규칙은 프로젝트의 메인 파트에서 금지되었던 모든 다양한 헤더, 라이브러리, 또는 함수들을 추가하여야 합니다. 보너스 과제는 반드시 _bonus.{c/h}라는 별도의 파일에 있어야 합니다. 반드시 수행하여야 하는 메인 파트의 평가와 보너스 파트의 평가는 별도로 이뤄집니다.

 

만일 프로젝트에서 여러분의 libft 사용을 허용한다면, 소스들과 관련 Makefile을 함께 루트 폴더 안에 있는 libft 폴더에 복사해야 합니다. 프로젝트의 Makefile은 우선 libft의 Makefile을 사용하여 라이브러리를 컴파일한 다음, 프로젝트를 컴파일해야 합니다.

 

이 과제물을 제출할 필요가 없고, 채점 받을 필요가 없을지라도, 저희는 여러분들이 프로젝트를 위한 테스트 프로그램을 만들 것을 권장합니다. 이것은 여러분의 과제물과 동료들의 과제물을 쉽게 테스트할 수 있게 도울 것입니다. 또한, 평가를 진행할 때 이러한 테스트 프로그램들이 특히 유용하다는 사실을 알게 될 것입니다. 평가 시에는 여러분의 테스트 프로그램과 평가 받는 동료의 테스트 프로그램들을 당연히 자유롭게 사용할 수 있습니다.

 

할당된 git 저장소에 과제물을 제출하세요. 오직 git 저장소에 있는 과제물만 등급이 매겨질 것입니다. Deepthought가 평가하는 과제의 경우엔, 동료평가 이후에 Deepthought가 수행됩니다. 만약 Deepthought 평가 중에 오류가 발생한다면, 그 즉시 평가는 중지될 것입니다.

 

Mandatory part

프로그램 이름 libft.a
제출할 파일 *.c, libft.h
Makefile 만드세요
사용가능한
외부 함수
자세한 내용은 아래를 확인하세요
설명 42 과정을 진행하면서 유용하게 쓰일 수 있는 함수들을 담은, 여러분만의 라이브러리를 작성하세요

 

Technical considerations

전역변수는 사용할 수 없습니다.

 

복잡한 함수를 구현하기 위해 하위 함수 (subfunction) 을 작성해야 한다면, 이러한 함수들을 static 으로 선언하여 라이브러리와 함께 컴파일되는 것을 막는 것이 좋습니다. 이러한 습관은 나중의 프로젝트를 진행할 때도 도움이 될 거에요.

 

모든 파일을 레포지토리의 루트 폴더에 제출하세요.

 

사용하지 않는 파일의 제출은 금지됩니다.

 

모든 .c 파일은 플래그와 함께 컴파일되어야 합니다.

 

반드시 ar 명령어를 사용하여 라이브러리를 생성하여야 합니다. libtool 명령어는 사용이 금지됩니다.

 

Part 1 - Libc functions

첫 번째 파트에서는, man에 정의되어 있는 그대로 libc 함수들을 새로 구현하셔야 합니다. 여러분의 함수들은 원본과 같은 프로토타입으로 선언되어야 하며, 같은 방식으로 동작해야 합니다. 다만 함수의 이름 앞에는 "ft_"를 붙여야 합니다. 예를 들면, strlen을 구현한 함수의 이름은 ft_strlen이 됩니다.

 

여러분이 재구현하여야 하는 함수들 중 일부는 원본의 프로토타입에 "restrict" 한정자가 사용됩니다. 이 키워드는 c99 표준에 해당하므로, 여러분의 라이브러리 프로토타입들에 이 키워드를 포함시키고 std=c99 플래그를 사용하여 컴파일하는 것은 금지됩니다.

 

여러분이 재구현하여야 하는 함수들 중 일부는 원본의 프로토타입에 "restrict" 한정자가 사용됩니다. 이 키워드는 c99 표준에 해당하므로, 여러분의 라이브러리 프로토타입들에 이 키워드를 포함시키고 std=c99 플래그를 사용하여 컴파일하는 것은 금지됩니다.

 

아래의 함수들을 다시 구현하세요. 이 함수들은 외부 함수를 필요로 하지 않습니다 :

 

ft_isalpha
알파벳인지 알아내는 함수

ft_isdigit
숫자인지 알아내는 함수

ft_isalnum
알파벳이나 숫자인지 알아내는 함수

ft_isascii
아스키코드인지 알아내는 함수

ft_isprint
출력가능한지 알아내는 함수

ft_strlen
문자열의 길이를 알아내는 함수

ft_memset
dest에 c를 n만큼 초기화한다.

unsigned char를 사용하는 이유 : unsigned는 내부 비트의 일부를 부호를 표현하기 위한 비트로 사용하지않고 모든 bit를 값을 표현하기 위한 용도로 사용을 함. 따라서 임의의 메모리에 바이트 단위로 접근해 값을 다룰 때에는 반드시 unsigned 키워드를 사용해야 제대로된 값을 얻을 수 있다.

ft_bzero
d 위치부터, n개만큼 0으로 초기화 하는 함수
이 함수는 더 이상 사용하지 않는 함수라고 한다.

ft_memcpy
src의 n만큼 dest에 복사한다.
만일 두 메모리 블록이 겹쳐져 있다면 undefined behavior가 나타난다.

ft_memmove
src 메모리 영역에서 dest 메모리 영역으로 n 바이트만큼 복사한다. 이 때, src 배열은 src와 dest의 메모리 영역과 겹치지 않는 메모리 영역부터 먼저 복사한다. 메모리 영역이 겹치는 경우는 한 배열 안에서 복사를 수행할 때이다.

ft_strlcpy
dest에 src를 n-1만큼 복사한다.
src의 '\0'값을 만나기 전 혹은 size - 1만큼 복사가 이루어 졌을때 복사를 중지한다. -1이 붙은 이유는 복사를 진행한 후 '\0'값을 넣어주기 위해서 그런 것이다. 이러한 이유로 strlcpy는 strcpy나 strncpy보다 안정성이 있는 함수이다.

ft_strlcat
dest 맨 뒤에 src를 n-1만큼 붙인다. 두 문자열을 합치는 함수다.
strlcpy와 같은 원리이다.

ft_toupper
알파벳 소문자일경우, 대문자로 변환한다.

ft_tolower
알파벳 대문자일경우, 소문자로 변환한다.

ft_strchr
str에서 i를 찾을 때 사용하는 함수. str에서 i를 찾는다면 해당 주소를 반환하고 찾지 못하면 NULL을 리턴한다.
str가 const로 선언되어서 char *로 형변환해서 반환한다.
find부분이 \0일경우 str[idx] == \0도 비교해야한다.

ft_strrchr
strchr과 마찬가지이나, 다른점은 뒤에서부터 찾는 함수
str이 빈 문자열일때나 s의 첫 문자만 c일 때, NULL이 아니라 s의 첫글자를 반환하도록 예외처리함.

ft_strncmp
s1, s2 두개의 문자열의 아스키코드값을 n만큼 비교한다.
s1이 더 크다면 양수 반환, s2가 더 크다면 음수 반환, 두 문자열을 다 비교해도 같다면 0 반환
ft_memset과 같은 이유로 unsigned char를 사용했다.

ft_memchr
src에서 c를 n만큼 찾는다. src의 값과 c의 값이 일치하면 src의 주소를 반환하고 아니라면 NULL을 반환한다.
return값에서 const 키워드때문에 컴파일 오류가 났어서, void *로 형변환을 함.

ft_memcmp
strncmp와 비슷하다. 하지만 몇가지 다른점이 있다.
매개변수를 char *가 아닌 void *로 받아온다.
두 문자열 중 하나가 끝나더라도(널 값이 나오더라도) 상관없이 서로 다른 값이 나오거나, n개가 될 때 까지 비교를 수행한다. 오버플로우는 처리를 못해주는 것 같다. 같은 문자열인데도 n값을 크게 주면 0이 아니라 쓰레기값끼리 비교한 값을 리턴한다. 항상 n은 버퍼 사이즈보다 같거나 작게.
strncmp는 s1과 s2가 모두 NULL값이 나오면 남은 카운트에 관계없이 0을 반환했던 것과 차이가 있다.

ft_strnstr
len 이하의 big 에서 little 를 검색하여 가장 먼저 나타나는 곳의 위치를 리턴한다.
이 때 일치하는 문자열이 없다면 널 포인터를 리턴하게 된다.
검색에서 마지막 널 문자는 포함하지 않는다
남은 size의 길이가 l_len 길이 보다 작다면, 비교할 의미가 없으므로 NULL을 리턴

ft_atoi
문자열을 숫자로 바꿔주는 함수다.
맨 앞부분의 공백을 처리해주고, 부호는 하나만 처리한다.
오버플로우 예외처리를 함.

long으로 선언한 이유
참고) https://smallpants.tistory.com/10

 

int와 long의 차이

long이 int보다 더 큰 범위를 보관할 수 있다고 보는것은 옳지 않다. int는 운영체제의 환경(32bit, 64bit 등)에 맞는 크기로 사용되어 왔는데 아래와 같이 16비트 운영체제에서는 16비트로 사용되었고 3

smallpants.tistory.com

 

다음의 함수들은 외부 함수 malloc 을 사용하여 구현하세요 :

 

ft_calloc
size 크기의 변수를 nmemb개 만큼 저장할 수 있는 메모리 공간을 할당한다.
그리고 동적으로 할당한 메모리의 모든 비트를 0으로 설정한다.

malloc과의 차이점
참고) https://bunhere.tistory.com/255

 

calloc vs malloc

둘 모두 메모리를 할당해준다는 점에서는 동일합니다. 하지만, 특정 상황에서는 어떤 것을 써야 할지 혼돈이 생기는 경우가 많습니다. 물론 대부분 calloc보다는 malloc을 쓰게 되는데 왜 이런 두

bunhere.tistory.com

ft_strdup
str 길이 + 1 크기를 malloc으로 할당 후 문자열 str을 복사한 후 반환하는 함수.
반환받은 메모리는 반드시 free를 통하여 메모리를 해제해야 한다.
malloc + strcpy

 

Part 2 - Additional functions

두 번째 파트에서는, libc에 포함되어 있지 않거나 다른 형식으로 포함된 함수들을 재구현하여야 합니다. 다음 함수들 중 일부는 Part 1 함수를 작성할 때 도움이 될 거에요.

 

ft_substr
매개변수
#1. 부분 문자열 (substring) 을 생성할 원본 문자열
#2. 부분 문자열의 맨 처음 인덱스
#3. 부분 문자열의 최대 길이

반환값
부분 문자열. 할당 실패 시, NULL

설명
malloc을 이용하여 메모리를 할당받은 후, 원본 문자열 's' 로부터 부분 문자열을 생성하여 반환합니다.
부분 문자열은 인덱스 'start' 부터 시작하며, 최대 길이 'len'을 갖습니다.

ft_strjoin
매개변수
#1. 접두 문자열 (prefix string)
#2. 접미 문자열 (suffix string)

반환값
새로운 문자열. 할당 실패 시, NULL

설명
malloc을 이용하여 메모리를 할당받은 후, 문자열 's1' 과 's2' 를 이어붙인 새로운 문자열을 생성하여 반환합니다.

ft_strtrim
매개변수
#1. 양 쪽을 잘라낼 원본 문자열
#2. 제거될 문자들의 집합

반환값
문자가 제거된 문자열. 할당 실패 시, NULL

설명
malloc을 이용하여 메모리를 할당받은 후, 's1'의 양 쪽 끝에서 'set'에 지정된 문자들이 제거된 문자열 사본을 반환합니다.

ft_split
매개변수
#1. 분할할 문자열
#2. 구분자 (delimiter)

반환값
split을 통해 분할된 문자열의 배열. 할당 실패 시, NULL

설명
malloc을 이용하여 메모리를 할당받은 후, 구분자 'c' 를 기준으로 문자열 's'를 분할하여 그 결과를 담은 새로운 문자열 배열을 반환합니다. 문자열 배열의 끝은 NULL 포인터로 끝나야 합니다.

ft_itoa
매개변수
#1. 변환할 정수

반환값
정수를 표현하는 문자열. 할당 실패 시, NULL

설명
malloc을 이용하여 메모리를 할당받은 후, 인자로 받은 정수를 나타내는 문자열을 반환합니다. 음수 또한 무조건 처리되어야 합니다.

ft_strmapi
매개변수
#1. 함수를 적용할 문자열
#2. 문자열의 각 문자에 적용할 함수

반환값
원본 문자열에서 함수 'f'를 성공적으로 적용하여 생성된 결과 문자열. 할당 실패 시, NULL

설명
문자열 's' 의 각 문자를 순회하며 함수 'f'를 적용하고, 해당 문자의 인덱스를 함수 'f'의 첫 번째 인자로 사용합니다. 각 문자에 함수가 적용된 새로운 문자열을 생성합니다 (malloc을 이용하여 메모리를 할당)

ft_striteri
매개변수
#1. 함수를 적용할 문자열
#2. 문자열의 각 문자에 적용할 함수

반환값
없음

설명
문자열 's' 의 각 문자를 순회하며 함수 'f'를 적용하고, 해당 문자의 인덱스를 함수 'f'의 첫 번째 인자로 사용합니다. 또한 각 문자의 주소값이 'f' 함수의 두 번째 인자로 사용되며, 경우에 따라 수정될 수 있습니다.

ft_putchar_fd
매개변수
#1. 출력할 문자
#2. 값이 쓰여질 파일 식별자 (file descriptor)

반환값
없음

설명
제공받은 파일 식별자에 문자 'c'를 출력합니다.

ft_putstr_fd
매개변수
#1. 출력할 문자열
#2. 값이 쓰여질 파일 식별자 (file descriptor)

반환값
없음

설명
제공받은 파일 식별자에 문자열 's'를 출력합니다.

ft_putendl_fd
매개변수
#1. 출력할 문자열
#2. 값이 쓰여질 파일 식별자 (file descriptor)

반환값
없음

설명
제공받은 파일 식별자에 문자열 's'를 출력하고, 개행을 출력합니다.

ft_putnbr_fd
매개변수
#1. 출력할 정수
#2. 값이 쓰여질 파일 식별자 (file descriptor)

반환값
없음

설명
제공받은 파일 식별자에 정수 'n'를 출력합니다.

 

Bonus part

필수 파트의 과제를 모두 수행하셨다면, 그보다 더 나아가는 것도 좋은 경험이 될 거에요. 이 마지막 섹션을 통해 보너스 점수를 얻어 보세요.

 

메모리와 문자열을 다루는 함수는 아주 유용하게 사용할 수 있죠. 지금부터 여러분은 리스트를 다루는 함수가 얼마나 더 유용한 지 알 수 있을 거에요.

 

make bonus 는 libft.a 라이브러리에 보너스 함수들을 추가합니다.

 

리스트의 요소들을 표현하기 위해 다음과 같은 구조체를 사용하세요. 이 구조체를 libft.h 파일에 추가하여야 합니다.

typedef struct s_list
{
    void          *content;
    struct s_list *next;
}              t_list;

다음은 t_list 구조체의 각 필드에 대한 설명입니다 :

 

content: 요소에 포함된 데이터. void * 를 통해 어떠한 자료형의 값도 담을 수 있습니다.

next: 다음 요소의 주소값. 만약 해당 요소가 마지막 요소라면, NULL을 가리킵니다.

 

다음의 함수들은 리스트를 쉽게 다룰 수 있도록 돕습니다.

 

ft_lstnew
매개변수
#1. 새로운 요소에 들어갈 content

반환값
새로운 요소 (element)

설명
malloc을 통해 메모리를 할당하고 새로운 요소를 반환합니다. 요소 내의 변수 'content' 는 인자로 받아온 'content' 로 초기화되어야 합니다. 요소 내의 변수 'next'는 NULL로 초기화되어야 합니다.

ft_lstadd_front
매개변수
#1. 리스트의 맨 앞에 위치한 요소
#2. 리스트에 추가할 요소

반환값
없음

설명
요소 'new'를 리스트의 맨 앞에 추가합니다.

ft_lstsize
매개변수
#1. 리스트의 맨 앞에 위치한 요소

반환값
리스트의 길이

설명
리스트에 포함된 요소의 개수를 셉니다.

ft_lstlast
매개변수
#1. 리스트의 맨 앞에 위치한 요소

반환값
리스트의 맨 마지막 요소

설명
리스트의 맨 마지막에 위치한 요소를 반환합니다.

ft_lstadd_back
매개변수
#1. 리스트의 맨 앞에 위치한 요소의 포인터
#2. 리스트의 맨 끝에 추가할 요소

반환값
없음

설명
요소 'new'를 리스트의 맨 뒤에 추가합니다.

ft_lstdelone
매개변수
#1. 삭제할 요소
#2. 요소의 content 삭제에 사용되는 함수 포인터

반환값
없음

설명
첫 번째 인자값으로 받은 요소의 content를 두 번째 인자로 받은 함수 포인터를 이용해 해제하고, 요소 자체의 메모리를 해제합니다. next 포인터는 해제하면 안 됩니다.

ft_lstclear
매개변수
#1. 삭제할 요소의 포인터
#2. 요소의 content 삭제에 사용되는 함수 포인터

반환값
없음

설명
함수 'del' 과 free를 이용하여 인자값으로 받은 요소와 그 뒤에 따라오는 리스트의 모든 요소들을 삭제하고 해제합니다. 마지막으로, 리스트의 포인터는 NULL로 설정되어야 합니다.

ft_lstiter
매개변수
#1. 리스트상의 요소
#2. 리스트 내에서 반복 적용될 함수 포인터

반환값
없음

설명
리스트 'lst' 를 순회하며, 리스트에 포함된 모든 요소들의 content에 함수 'f'를 반복적으로 적용시킵니다.

ft_lstmap
매개변수
#1. 리스트상의 요소
#2. 리스트 내에서 반복 적용될 함수 포인터
#3. 필요할 경우, 요소의 content를 삭제하는 데에 사용되는 함수

반환값
새로운 리스트. 할당 실패 시, NULL

설명
리스트 'lst'의 요소들을 순회하며 각 요소의 content에 함수 'f'를 연속적으로 적용시킵니다. 또한 함수 'f'를 적용시킨 결과물들을 content로 담은 새로운 리스트를 생성합니다. 'del' 함수들은 필요 시 각 요소의 content를 삭제하는 데 사용됩니다.

 

소스코드 참고

https://github.com/dc-choi/42_libft

 

GitHub - dc-choi/42_libft

Contribute to dc-choi/42_libft development by creating an account on GitHub.

github.com

 

프로젝트를 진행하면서 느낀점

이번 프로젝트는 피신때 쌓은 지식을 다시 정제한다는 느낌이 들었습니다.

진행하면서 피신때 사용했던 함수들도 있고, 사용하지않은 함수들도 있었는데 함수들을 직접 구현해보면서, 내가 놓치고있던 개념이 무엇이였는지 다시 한번 리마인드하게 될 수 있던 프로젝트였습니다.

반응형

'42 Seoul' 카테고리의 다른 글

[42 Seoul] Born2BeRoot 설정가이드(Debian)  (0) 2022.05.13
[42 Seoul] Born2BeRoot 설치가이드(Debian)  (0) 2022.05.12
[42 Seoul] Born2beRoot  (0) 2022.05.09
[42 Seoul] Printf  (0) 2022.04.22
[42 Seoul] Get Next Line  (0) 2022.03.07