42Seoul/Libft

[C] 나만의 라이브러리 - split 함수 구현

  • -
728x90

split

함수 형태

char **my_split(char const *s, char c);

매개 변수

  • 분할할 문자열
  • 구분 기호 문자

반환 값

분할한 새 문자열 배열, 할당 실패시 NULL 반환

설명

malloc(3)로 할당하고 문자 'c'를 구분 기호로 사용하여 's'를 분할하여 얻은 문자열 배열을 반환하십시오. 배열을 NULL 포인터로 종료해야 함

소스 코드

#include "libmy.h"

static int    get_row(char const *s, char c)
{
    size_t    i;
    size_t    ret;

    i = 0;
    ret = 0;
    while (s[i])
    {
        if (s[i] != c && (s[i + 1] == c || !s[i + 1]))
            ret++;
        i++;
    }
    return (ret);
}

static int    get_split(char const *s, char c, char **ret)
{
    char    *flag;
    size_t    col;
    size_t    i;
    size_t    j;

    col = 0;
    i = 0;
    j = 0;
    flag = 0;
    while (*s)
    {
        if (*s != c)
        {
            if (!flag)
                flag = (char *)s;
            col++;
            if(*(s + 1) == c || !*(s + 1))
            {
                if (!(ret[i] = (char *)my_calloc(col + 1, sizeof(char))))
                    return (0);
                while (j < col && flag[j])
                {
                    ret[i][j] = flag[j];
                    j++;
                }
                i++;
                flag = 0;
                col = 0;
                j = 0;
            }
        }
        s++;
    }
    return (1);
}

char        **my_split(char const *s, char c)
{
    char    **ret;
    size_t    row;

    row = 0;
    while (*s && *s == c)
        s++;
    if (!(row = get_row(s, c)))
        return ((char **)s);
    if (row == my_strlen(s) || !s)
        return (0);
    if (!(ret = (char **)my_calloc(row + 1, sizeof(char))))
        return (0);
    if (get_split(s, c, ret))
        return (ret);
    else
        return (0);
}

테스트 케이스를 돌렸을 때 segmentation fault가 떳다. 이유가 뭘까.. 직접 넣어본 테스트는 잘 되는거 같았는데 너무 어렵다...

다 지우고 코드를 다시 작성해봤다.

#include "libmy.h"

static char		**my_free_malloc_error(char **ret)
{
	size_t	i;

	i = 0;
	while (ret[i])
	{
		free(ret[i]);
		i++;
	}
	free(ret);
	return (NULL);
}

static size_t	my_get_row(char const *s, char c)
{
	size_t	ret;
	size_t	i;

	ret = 0;
	i = 0;
	if (!*s)
		return (0);
	while (s[i] && s[i] == c)
		i++;
	while (s[i])
	{
		if (s[i] == c)
		{
			ret++;
			while (s[i] && s[i] == c)
				i++;
		}
		else
			i++;
	}
	if (s[i - 1] != c)
		ret++;
	return (ret);
}

static size_t	my_get_strlen(char const *s, char c)
{
	size_t	i;

	i = 0;
	while (s[i])
	{
		if (s[i] == c)
			break ;
		i++;
	}
	return (i);
}

char			**my_split(char const *s, char c)
{
	char	**ret;
	size_t	len;
	size_t	row;
	size_t	i;

	if (!s)
		return (NULL);
	row = my_get_row(s, c);
	if (!(ret = (char **)malloc(sizeof(char *) * (row + 1))))
		return (NULL);
	i = 0;
	while (i < row)
	{
		while (*s && *s == c)
			s++;
		len = my_get_strlen(s, c);
		if (!(ret[i] = (char *)malloc(sizeof(char) * len + 1)))
			return (my_free_malloc_error(ret));
		my_strlcpy(ret[i], s, len + 1);
		i++;
		if (i < row)
			s += len;
	}
	ret[i] = (NULL);
	return (ret);
}

문제를 다시 읽어보니 malloc함수를 이용하여 풀으라고 돼있었다. segfault의 원인은 아마 스플릿 문자 확인할 때 다음 문자확인용도로 +1 했던게 문제가 아닐까 싶다.
그리고 또 중요한 것은 메모리 할당에 실패했을 때 누수 처리도 해주어야한다. 행에 대한 누수처리는 실패시 NULL을 반환하면 되지만 열에 대한 누수처리는 그 전까지 할당된 메모리를 모두 해제해야한다.
하지만 abort 에러가 떳다. 그 이유는 strlcpy에 있었다.

size_t    my_strlcpy(char *dst, const char *src, size_t size)
{
    const char    *s;
    char        *d;
    size_t        n;

    d = dst;
    s = src;
    n = size;
    if (!dst && !src)
        return (0);
    if (n != 0)
    {
        while (--n != 0)
        {
            if ((*d++ = *s++) == '\0')
                break ;
        }
    }
    if (n == 0)
    {
        if (size != 0)
            *d = '\0';
        while (*s++)
            ;
    }
    return (s - src - 1);
}

while(*s++)을 하게되면 조건에서 *s가 널문자임을 확인하고 다음으로 넘어가버려서 문제가 됐었다.
코드 수를 줄이고 좀 간편하게 풀려고 하다가 틀리는 경우가 많다. 정말 사소한부분까지 잘 보면서 문제를 풀어야한다.

728x90
300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.