Part2 Additional functions
String 함수들
대부분 malloc를 사용해야 하는 함수. malloc으로 동적 할당에 실패할 경우 NULL을 반환하므로 항상 동적 할당한 포인터가 NULL인지 확인해 적절한 처리를 해주어야 한다. malloc실패에는 너무 큰 크기의 요청, 음수 혹은 0 크기의 할당 요청, 메모리 부족 등등.....
1. ft_substr
-
Prototype
char *ft_substr(char const *s, unsigned int start, size_t len) -
함수 동작
= 문자열 s의 start 위치부터 len길이만큼을 새로운 메모리를 할당(동적 할당)해 저장한 뒤 반환
= return : 할당에 실패할 경우 NULL을 반환 -
구현 방법
동적 할당에 실패했을 경우에만 NULL을 반환하라고 작성되어 있어서 s가 널 포인터 이거나, start값이 문자열 s의 길이보다 클 경우 ft_strdup함수를 사용해 free 할 수 있는 빈 문자열을 반환
위의 두 가지 조건을 확인한 뒤 동적 할당하여서, 문자열 s의 start위치부터 새로 할당받는 배열에 차례대로 복사를 수행한 뒤 마지막에 NULL을 넣어준 뒤 반환 -
주의할 점
동적 할당을 해줄 때 문자열의 끝을 알려주는 NULL까지 생각해서 할당을 해줘야 한다.
2. ft_strjoin
-
Prototype
char *ft_strjoin(char const *s1, char const *s2) -
함수 동작
= 새로운 메모리를 할당(동적 할당)해 전달 인자로 들어온 문자열 s1과 s2를 차례로 저장한 뒤 반환
= return : 할당에 실패할 경우 NULL을 반환 -
구현 방법
ft_strlen(s1) + ft_strlen(s2) + 1의 크기로 동적 할당을 하고, 앞에서부터 차례대로 복사를 수행하면 된다.
if (!(ret = (char *)malloc(ft_strlen(s1) + ft_strlen(s2) + 1)))
return (0);
ft_memcpy(ret, s1, ft_strlen(s1));
ft_memcpy(ret + ft_strlen(s1), s2, ft_strlen(s2) + 1);
return (ret);
3. ft_strtrim
-
Prototype
char *ft_strtrim(char const *s1, char const *set) -
함수 동작
= 문자열 s1의 앞과 뒤에서 연속적으로 set에 포함된 문자들을 제거해준 뒤 새로운 메모리를 할당해 저장한 뒤 반환
= return : 할당에 실패할 경우 NULL을 반환 -
구현 방법
아래 그림처럼 문자열 s1의 맨 앞, 맨뒤 인덱스를 나타내는 start, end 변수를 선언해서 set에 포함된 문자라면 start는 증가, end는 감소. (아래의 그림에서 set = "xy")


start와 end의 값이 정해지면 이제 두 값을 비교해 동적 할당 및 복사를 수행해야 한다. 만약 start가 end보다 클 경우 문자열 s1의 모든 요소가 set에 포함된 경우이기 때문에 복사를 수행하지 않고 ft_strdup를 사용해 free 할 수 있는 빈 문자열을 반환한다. 이 경우가 아니라면 end - start + 2 (NULL문자 포함) 크기로 동적 할당을 수행해 문자열 s1의 start부터 end까지 복사해서 반환해준다.
-
주의할 점
= set혹은 s1이 NULL Pointer가 들어왔을 경우의 예외처리를 해주어야 한다.
4. ft_split
-
Prototype
char **ft_split(char const *s, char c) -
함수 동작
= 문자열 s를 구분자 c로 구분하여 여러 개의 문자열로 나누어 각 문자열을 동적 할당받은 배열에 저장해서 반환, 마지막에는 NULL이 들어가야 한다. -
구현 방법
static int get_count(char const *s, char c)
{
int i;
int count;
count = 0;
i = 0;
while (s[i])
{
if (i == 0)
{
if (s[i] != c)
count++;
}
else
{
if (s[i] != c && s[i - 1] == c)
count++;
}
i++;
}
return (count);
}
우선 문자열 s가 구분자 c를 기준으로 몇 개의 문자열로 나누어지는지 계산해주는 get_count함수를 작성하였다. 그리고 char** 자료형을 get_count의 반환 값 + 1 크기로 동적 할당해 주어야한다.


왜 get_count+1만큼 동적 할당을 해야 할까? (위의 그림은 설명을 돕기 위한 것)
위의 그림처럼 s가 들어왔고 구분자가 스페이스(' ')라면 ret 배열을 반환해 주어야 한다. 위의 경우 get_count함수의 반환 값은 4("abc", "dd", "123", "xxxx")가 되는데 여기에 문제의 요구사항에 작성되어있는 마지막은 NULL로 끝내야 한다 를 만족하기 위해 마지막에 추가로 NULL을 넣어줄 공간 하나를 더 추가해야 하기 때문에 get_count + 1만큼 동적 할당을 해주어야 한다.

get_count + 1만큼 동적 할당한 결과. 현재 ret는 5개의 char *를 가리키고 있다. 이제 각 char *마다 다시 동적 할당을 해주어야 한다. ret[0] (첫 번째 char *)은 "abc"를 저장해야 하므로 4만큼 ret[1]은 "dd"를 저장해야 하므로 3만큼... 동적 할당을 해주어야 한다다. 이후 값을 복사해 ret를 반환하면 된다.

while (s[index])
{
if (s[index] != c)
{
start = index;
while (s[index] && s[index] != c)
index++;
if (!mem_alloc(ret, ret_index, index - start + 1))
return (0);
ft_strlcpy(ret[ret_index++], &(s[start]), index - start + 1);
}
else
index++;
}
index가 구분자가 아니라면(문자열의 첫 시작이라면) start에 해당 index를 저장한 뒤 다음 구분자가 나타날 때까지 index를 증가시켰다. 그럼 index는 다음 구분자 혹은 NULL의 위치를 가지고 있다. 그렇다면 index - start이 이번에 자를 문자열의 길이가 된다.
동적 할당은 index - start + 1만큼 해주는데 strtrim에서는 start위치와 end의 위치 모두 복사를 수행해야 하기 때문에 널문자 포함 +2를 하였고, 이번 index위치는 복사할 필요가 없는 위치이기 때문에 널문자를 추가할 +1만 하였다.
복사할 문자열의 길이만큼 동적 할당을 해주었다면 ft_strlcpy를 사용해 start위치부터 index- start + 1만큼 복사를 하면 된다. ft_strlcpy는 NULL문자를 보장해주기 때문에 index - start의 문자 복사가 이뤄지고 마지막에는 자동으로 NULL문자를 넣어준다.
ft_split에서 메모리를 할당하고, 해제해주는 함수를 따로 작성하였다.(중간에 할당 실패를 잡기위해)
static void mem_free(char **ret, size_t count)
{
size_t i;
i = 0;
if (count > 0)
while (i < count)
free(ret[i++]);
free(ret);
}
static int mem_alloc(char **ret, size_t index, size_t size)
{
if (!(ret[index] = (char *)malloc(size)))
{
mem_free(ret, index);
return (0);
}
return (1);
}
5. ft_itoa
-
Prototype
char *ft_itoa(int n) -
함수 동작
= 정수 n을 문자열 형태로 변환한 뒤 동적 할당한 메모리에 저장 후 반환 -
구현 방법
= n이 몇 자릿수인지 계산하여 자릿수만큼 동적 할당해주어 각 자리값을 계산해 넣어준 뒤 반환해주면된다. -
주의할 점
= n이 음수일 경우 '-'가 들어갈 공간이 필요하므로 양수일 때보다 공간이 하나 더 필요하다.
= 구현 방법에 따라 다르겠지만 음수일 경우 -1을 곱해주어 양수로 바꾸어주었는데 int형의 최솟값이 들어올 경우 오버플로우가 발생하므로 int형보다 큰 자료형으로 변경 후 사용해 주어야 한다.
= 구현 방법에 따라 다르겠지만 0이 들어왔을 때 처리를 해주어야 한다.
6. ft_strmapi
-
Prototype
char *ft_strmapi(char const *s, char (*f)(unsigned int, char)) -
함수 동작
= 전달 인자로 문자열의 index와 해당 index의 문자를 받는 함수 f의 결과를 동적 할당해 저장한 뒤 반환 -
구현 방법
= 함수 f의 결괏값은 문자열 s의 길이만큼 나오므로, ft_strlen(s) + 1만큼(NULL문자 포함) 동적 할당한다.
= 문자열 s의 첫 번째 문자부터 차례대로 함수 f를 적용 시킨다.
= 함수 f의 결과를 동적 할당받는 배열에 저장한다. -
함수 포인터
= 함수 포인터 f는 반환 값이 char형이고 전달 인자로는 unsigned int와 char를 받는다.
-> unsigned int에는 문자열 s의 index , char에는 문자열 s의 i번째 요소(s[i])를 받는다.
if (!(ret = (char *)malloc(sizeof(char) * (size + 1))))
return (0);
while (i < size)
{
ret[i] = f(i, s[i]);
i++;
}
ret[i] = 0;
출력 관련 함수들
화면에 출력하는 문제에서 write(1, x, x)처럼 사용하였는데 1은 표준 출력을 나타내는 fd이다.
7. ft_putchar_fd
-
Prototype
void ft_putchar_fd(char c, int fd) -
함수 동작
= fd로 문자 c를 출력 -
구현 방법
= write함수의 첫 번째 인자가 fd이다. 화면에 출력할 때는 표준 출력을 나타내는 1을 사용하였고, 이번에는 fd를 넣어주면 된다.
8. ft_putstr_fd
-
Prototype
void ft_putstr_fd(char *s, int fd) -
함수 동작
= fd로 문자열 s를 출력
9. ft_putendl_fd(char *s, int fd)
-
Prototype
void ft_putendl_fd(char *s, int fd) -
함수 동작
= fd로 문자열 s와 개행을 출력 -
구현 방법
= ft_putstr_fd를 사용해 문자열 s를 출력한 뒤 ft_putchar_fd를 사용해 '\n'을 출력
9. ft_putnbr_fd(int n, int fd)
-
Prototype
void ft_putnbr_fd(int n, int fd) -
함수 동작
= fd로 정수 n을 출력