Developer

Part2 Additional functions 본문

42seoul/Libft

Part2 Additional functions

DPhater 2020. 8. 17. 19:04

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 초기
set에 포함된 문자 start,end 각각 증가 및 감소 후

       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
Comments