자주 사용하게 되는 메서드들을 구현하는 프로젝트이다.
이후에 진행할 프로젝트들에서 실제 메서드들을 사용할 수 없으니
이번 프로젝트에서 구현한 메서드들을 사용한다는 느낌으로 진행하였다.
메서드 | 설명 |
---|---|
int ft_isalpha(int c); | c가 알파벳이 아니면 0, 대문자면 1, 소문자면 2 반환 |
int ft_isdigit(int c); | c가 숫자가 아니면 0, 숫자면 0이 아닌 숫자 반환 |
int ft_isalnum(int c); | c가 알파벳과 숫자 모두 아니면 0, 알파벳 또는 숫자면 0이 아닌 수 반환 |
int ft_isascii(int c); | c가 아스키 코드면 1, 아니면 0 반환 |
int ft_isprint(int c); | c가 출력할 수 없는 값이면 0, 출력할 수 있는 문자면 0이 아닌 수 반환 |
이 메서드들은 설명을 간단히 할 수 있으므로 표로 만들었다.
size_t ft_strlen(const char *str);
const char *str
문자열문자열의 길이를 반환하는 메서드이다.
void *ft_memset(void *ptr, int value, size_t num)
void *ptr
세팅하고자 하는 메모리의 시작 주소int value
메모리에 세팅하고자 하는 값size_t num
메모리의 크기(sizeof(int) * length
)ptr
주소value
값을 num
길이만큼 ptr
에 넣어주는 메서드입니다.
void ft_bzero(void *ptr, size_t size);
void *ptr
메모리 주소size
0으로 채울 길이ptr
을 처음부터 size
만큼 0으로 채워주는 메서드.
void *ft_memcpy(void *dest, const void *src, size_t num)
void *dest
복사 받을 메모리const void *src
복사할 메모리size_t num
복사 길이*dest
원본(src
)을 길이(num
)만큼 dest
에 복사하는 메서드.
주의점 : 마지막에 \0
는 따로 넣어줘야한다. 이로 인해 길이도 +1을 해줘야한다.
void *ft_memmove(void *dest, const void *src, size_t num);
void *dest
복사 받을 메모리const void *source
복사할 메모리size_t num
복사 길이*dest
memcpy
와 매개변수와 반환이 똑같지만 내부 로직이 다르다.
memcpy
는 속도가 빠르지만 안전하지 않고,
memmove
는 속도가 느리지만 안정성이 보장되어 있다.
안전하지 않다는 것이 어떤 의미인지 설명해보겠다.
memcpy
를 사용할 경우 맨 앞에서부터 복사를 하기 시작하므로,
s r c
d e s t
이런식으로 복사한 결과값이 될 dest
의 메모리가 src
의 중간에 있다면 어떻게 될까?
만약에 src
가 12345
라고 하고 dest
의 첫번째 메모리가 src
의 3
부터 있다고 가정해보자.
1 2 3 4 5
1 2 1 2 1
dest
는 이와 같이 될 것이다. 왜 이렇게 되는지 알겠는가?
이는 맨 앞에서부터 복사를 하기 시작하므로 생겨난 일인데, 처음에 src
의 12
까지는 dest
가 똑같이 12
를 복사하게 된다.
그런데 src
의 세번째 인덱스값 3
는 dest
의 첫번째가 덮어버려서 3
이 아니라 1
이 들어있게 된다. 이 숫자 1
을 복사하게 되니, dest
의 세번째 인덱스값은 1
이 되는 것이다.
이와 같이 복사를 계속하게 되면 12121
이 나오게 된다.
하지만, memmove
는 이 경우에도 dest
를 12345
로 만들어준다.
어떤 로직을 사용해야 할까?
나는 이를 구현할때
src
의 주소값이 dest
보다 앞에 있다면 뒤부터 값을 복사한다.
src
의 주소값이 dest
보다 뒤에 있다면 앞부터 값을 복사한다.
이 방법을 사용하였다.
이렇게 된다면 src
의 값은 수정되겠지만, dest
값은 변하지 않고 처음 src
값이 들어가게 된다.
size_t ft_strlcpy(char *dest, const char *src, size_t size);
void *dest
복사 받을 메모리const void *source
복사할 메모리size_t size
복사 길이dest
길이size
가 src
의 길이 이하일때는 size - 1
만큼 복사(size 길이에 \0
포함)
이외는 src
를 dest
로 복사
size_t ft_strlcat(char *dst, const char *src, size_t size)
void *dest
기본 메모리const void *source
dest
뒤에 붙일 메모리size_t size
총 길이dest
길이3가지 경우로 나뉘게 된다.
size
가 dest
길이보다 작은 경우dest
길이 반환size
가 dest
길이보다 크고 dest
+ src
길이 이하인 경우dest
길이가 size - 1
이 될 때까지 dest
뒤에 src
를 붙이고 최종 dest
길이 반환size
가 dest
+ src
길이보다 큰 경우dest
뒤에 src
를 전부 붙인 후, 최종 dest
길이 반환int ft_strncmp(const char *s1, const char *s2, size_t n)
const char *s1
비교할 문자열1const char *s2
비교할 문자열2size_t n
비교할 길이0
s1
이 크면 양수s2
가 크면 음수비교할 길이(n
)만큼 각 문자열의 아스키 코드를 비교한다.
더 큰 쪽이 있다면 어느쪽이 큰지 비교 후 반환한다.
ex) s1
, s2
, n
abcd
, abce
, 10
-> -1
abcd
, abce
, 2
-> 0
abce
, abcd
, 10
-> 1
void *ft_calloc(size_t nmemb, size_t size)
size_t nmemb
동적할당 길이size_t size
동적할당 이후 0으로 채울 길이malloc
과의 차이점
말록은 매개변수가 '동적할당 길이' 하나이다. 그리고 안에는 쓰레기값
으로 채워져있다.
칼록의 경우 두번째 매개변수(size
)만큼 0으로 채워준다.
char *ft_strdup(const char *s)
const char *s
새롭게 동적할당 해줄 문자열문자열 s
의 길이만큼 새롭게 동적할당을 한다.
거기에 s
문자열을 복사한다.
그걸 반환한다.
char *ft_substr(char const *s, unsigned int start, size_t len)
const char *s
자르려는 문자열unsigned int start
자르려는 시작점size_t len
자르려는 길이빈 문자열을 동적할당하여 반환하는 경우
s
의 길이가 start
보다 작을때len
이 0
일 때s
가 NULL일 때마지막 s
가 NULL일때 그냥 NULL 반환하는 경우도 있다. 여러 이야기가 있기 때문에 확실하지 않는 정보이다.
이외에는 start
지점부터 len
길이만큼 문자열 s
의 내용을 새로운 동적할당에 복사한다. 그리고 이 문자열을 반환한다.
char *ft_strjoin(char const *s1, char const *s2)
const char *s1
문자열1const char *s2
문자열2두 문자열 길이 합만큼 새로 동적할당을 한다.
s1
+ s2
로 새로 값을 넣어준다.
해당 문자열을 반환한다.
char *ft_strtrim(char const *s1, char const *set)
char const *s1
양쪽을 잘라낼 원본 문자열char const *set
제거할 문자열s1
을 set
으로 제거한 새로운 문자열s1
의 양쪽에 set
이 있다면 각각 제거해준다.
이를 malloc
을 이용해 새롭게 동적할당을 한 뒤에 반환해준다.
char **ft_split(char *s, char c)
char *s
원본 문자열char c
문자열을 나누는 기준s
문자열을 c
로 나눈 이중 문자열을 반환문자열 s
를 c
기준으로 나눈다.
abcdce
라는 문자열을 c
라는 문자열로 나눈다면,
ab
d
e
이렇게 이중 배열을 새롭게 동적할당해주고 반환한다.
42에서는 이 split
이 중요한 메서드로 불리기도 하는데, 동적할당을 중간에 실패했을 시에 어떻게 프로그램을 완성할 것인가가 중요한 메서드였다.
쉽게 말해 처음에 2중 말록을 통해 동적할당을 해준 후, 배열을 돌며 각 문자열을 동적할당하는 방식이 되는데
동적할당을 실패하게 되면, 보통 NULL
을 반환하게 되지만, split
메서드의 경우 동적할당을 계속 만들어주므로 중간에 동적할당을 실패하게 되면 이전까지 할당해줬던 값들을 free
를 통해 해제해준 다음에 NULL
을 반환해줘야한다.
메서드가 실패했을 경우, 예외 처리를 완벽히 해줘야 하는 것이다.
이 문제에 대해 여러 이야기가 오갔는데, 만약 NULL
반환이 아니라 해당 이중배열을 반환하게 되면 메모리 누수가 발생하지 않는다. 변수로 반환된 값을 받기 때문이다.
하지만, 할당 실패의 경우 NULL
을 반환하게 되므로, 이전의 동적할당 값들이 split
이라는 메서드 안에서 남겨지게 된다. 이 값들을 찾을 방도가 없는 것이다. 그렇기 때문에 메모리 누수가 발생하게 되므로, 동적할당을 해제하고 NULL
을 반환해주는 것이 맞다.
이것이 첫 프로젝트의 매운맛 버전이였다. 메서드의 동작 설명 뿐만이 아니라 이렇게 만들게 된 이유를 정확히 설명하는 것이 이 프로젝트의 목적이다.