일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- jupyter 단축키
- iF
- C언어
- 42Seoul
- 포인터
- vs코드 단축키
- libft
- python
- 패킹
- Double
- docker
- ft_server
- 동적할당
- phpmyadmin
- for
- list
- 42서울
- Class
- nginx
- 42cursus
- else if
- 구조체
- float
- 2차원배열
- 함수
- cout
- 42
- C++
- While
- 자료형
- Today
- Total
Developer
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을 출력
'42seoul > Libft' 카테고리의 다른 글
Bonus Part (1) | 2020.09.07 |
---|---|
Part1 - Libc functions (0) | 2020.08.15 |