[Libft] C 언어 라이브러리 구현_Part2_추가함수 구현2

2021. 5. 23. 18:13·IT/42Seoul

혹시나 문제가 된다면 바로 비공개 처리하겠습니다. 지적이나 댓글 환영합니다!

 

이번 포스팅에서는 이어서 문자열 관련 함수들을 구현해보겠다.

소개할 함수 3개의 공통점은 모두 동적할당(malloc)을 사용하여 편집된 문자열을 새로 만드는 것이다.

이번 함수들은 메뉴얼이 이미 과제 페이지에 영어로 상세히 적혀있는 대신, 전보다 구현이 복잡한 특징을 가졌다.

따라서 이번 시간에는 함수의 역할 대한 정리보다는 함수를 어떤 방식으로 구현했는지, 구현에서 어떤 문제들을 마주쳤고 이를 어떻게 해결했는 지 위주로 설명하겠다. (면접용 연습)

주의사항이라고 적은 사항들이 대부분 내가 실수했으나 고쳐서 어떻게 해결했는 지에 대한 내용들이다.

 

참고로, 내가 정의한 libft.h 헤더에는 <unistd.h>와 <stdlib.h>가 include 되어있다. 따라서 libft.h를 호출하면, 따로 정의하지 않고도 <unistd.h> 에 정의된 size_t 타입과 <stdlib.h>의 malloc/free를 사용할 수 있다.

 

 

 

 

(1) ft_split : 주어진 문자를 기준으로 문자열 쪼개기

: 주어진 문자열(1차원 배열)을 주어진 문자를 기준으로 쪼개서, 쪼개진 단어들을 동적할당한 2차원 배열에 넣는다.

 

 


- 구현 코드 예시 :

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "libft.h"
 
static int    ft_get_cnt(char const *s, char c)
{
    int i;
    int flag;
    int cnt;
 
    i = 0;
    cnt = 0;
    flag = 0;
    while (s[i])
    {
        flag = 0;
        while (s[i] && s[i] != c)
        {
            i++;
            flag = 1;
        }
        if (flag == 1)
            cnt++;
        if (s[i])
            i++;
    }
    return (cnt);
}
 
static char    *ft_strndup(char const *s, int size)
{
    char    *p;
    int        i;
 
    i = 0;
    if (!(p = malloc(sizeof(char) * (size + 1))))
        return (0);
    while (i < size)
    {
        p[i] = s[i];
        i++;
    }
    p[i] = '\0';
    return (p);
}
 
static char    **free_all(char **ptr)
{
    int i;
 
    i = 0;
    while (ptr[i])
    {
        free(ptr[i]);
        i++;
    }
    free(ptr);
    return (0);
}
 
static char    **ft_word_split(char **p, char const *s, char c)
{
    int    i;
    int    size;
    int    index;
 
    i = 0;
    index = 0;
    while (s[i] == c)
        i++;
    while (s[i])
    {
        size = 0;
        while (s[i + size] != c && s[i + size])
            size++;
        if (size == 0)
            i++;
        else
        {
            if (!(p[index++] = ft_strndup((s + i), size)))
                return (0);
            i += size;
        }
    }
    p[index] = 0;
    return (p);
}
 
char        **ft_split(char const *s, char c)
{
    char    **p;
    int        cnt;
 
    if (*s == 0)
    {
        if (!(p = malloc(sizeof(char *))))
            return (0);
        p[0] = 0;
        return (p);
    }
    cnt = ft_get_cnt(s, c) + 1;
    if (!(p = malloc(sizeof(char *) * cnt)))
        return (0);
    if (!(p = ft_word_split(p, s, c)))
        return (free_all(p));
    return (p);
}
 
Colored by Color Scripter
cs

- ft_get_cnt() 함수를 통해 문자 c로 구분되는 단어의 개수를 구한다.

- 단어의 개수 + 끝부분 null을 넣을 1칸을 추가하여 메모리를 할당한다.

 

- 메모리 할당이 성공했을 경우, ft_word_split() 함수를 통해 각각의 단어를 2차원 배열에 할당해준다.

- ft_strndup() 함수는 정해진 사이즈만큼 1차원 배열을 할당하고 복사하여 포인터를 리턴하는 함수이다. ft_word_split() 실행 중에, 구분자로 나눠진 단어를 복사하는 데 쓰였다. (char *) 배열의 1칸에 (char) 배열인 문자열 포인터를 받아와 붙여주는 식이다.

 

- 메모리 할당이 실패할 경우 남아있는 메모리들을 모두 free()해주기 위해서, free_all() 함수를 사용하였다.

 

 

- 주의할 점 : ft_word_split()이나 ft_strndup()에서는 malloc을 통한 메모리 할당을 사용한다. 이때 커널에 할당할 메모리가 부족할 경우, 리턴되는 포인터에 0을 받을 수 있다. (char) 1차 배열을 할당하고 복사하는 상황에서, 메모리가 다 할당되는데는 성공하지 못했어도, 이미 할당된 메모리가 남아있을 수 있다. 메모리 누수를 예방하려면 이러한 메모리들도 모두 free 해주어야 한다.

(안하면 "메모리 누수"로 판단되어 동료평가에서 0점 맞을 수 있음)

여기서 주의할 점은, (char *)을 할당하는 부분에서는 free()를 하지 않는다. 왜냐면 p에는 이미 메모리 할당 실패로 null이 들어가 있는 상태기 때문이다. 또한 이 경우는 할당한 메모리가 존재하지 않는다. 그러므로 free(p)가 free(null)과 다름 없이 해석되어 segfault 오류가 날 수 있다. (char *) 배열 할당 후, char 배열을 할당하는 시점에서 메모리 할당이 실패할 경우에만, 이미 할당되고 남아있는 메모리들을 free()로 정리해주는 것을 유의하자.

 

- 주의할 점 : 주어진 문자열 s가 빈 문자열일 경우, 할당된 p를 p[0] = 0 으로 처리하여 포인터를 리턴해야한다. 나는 이 예외처리 부분을 잡지 못해서 첫 트라이에서 segfault를 받은 것 같다. 

 

 

- 참고) 커널이란?

더보기

Linux 커널은 Linux 운영 체제(OS)의 주요 구성 요소이며, 컴퓨터 하드웨어와 프로세스를 연결하는 핵심 인터페이스이다.

자원 관리, 한정된 시스템 자원을 효율적으로 관리하여 프로그램의 실행을 원활하게 한다

 

 

 

 

(2) ft_itoa : 숫자를 문자열로 바꾸기

- Alphabet to Integer

- 정수를 문자열로 변환한 뒤, 그 문자열의 포인터를 리턴한다.

 

 


- 구현 코드 예시 :

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "libft.h"
 
static int    ft_nbr_len(int n, int cnt)
{
    if (n == 0 && cnt != 0)
        return (cnt);
    return (ft_nbr_len(n / 10, cnt + 1));
}
 
static int    ft_power_len(int n)
{
    int    gop;
 
    gop = 1;
    while (n--)
        gop *= 10;
    return (gop);
}
 
static char    *ft_strcpy(char *dst, char *src)
{
    int    i;
 
    i = 0;
    while (src[i])
    {
        dst[i] = src[i];
        i++;
    }
    dst[i] = '\0';
    return (dst);
}
 
char        *ft_itoa(int n)
{
    char    *p;
    int        len;
    int        i;
 
    len = ft_nbr_len(n, 0);
    if (n < 0)
        len++;
    p = malloc(sizeof(char) * (len + 1));
    if (!(p))
        return (0);
    if (n == -2147483648)
        return (ft_strcpy(p, "-2147483648"));
    i = 0;
    if (n < 0)
    {
        p[i++] = '-';
        n *= -1;
    }
    while (i < len)
    {
        p[i] = ((n / ft_power_len(len - 1 - i)) % 10) + '0';
        i++;
    }
    p[i] = '\0';
    return (p);
}
 
Colored by Color Scripter
cs

- 주의할 점 : 숫자를 양수로 바꾼 뒤 문자열로 변환하였기 때문에, int형 최솟값인 -2^31은 따로 예외처리 해주었다. 이 경우는 ft_strcpy를 통해, 이미 할당된 공간에 문자열 "-2147483648"를 복사하고, 이를 바로 리턴하였다.

 

 

- 재귀를 사용하는 ft_nbr_len() 함수를 통해, 숫자의 길이를 구하여 len에 저장한다. 만일 숫자가 음수인 경우, 부호 부분의 길이인 1을 더해준다.

- 구한 숫자의 길이 + 1 만큼 malloc으로 메모리를 할당해준다.

- 앞에서부터 숫자를 하나씩 떼서 그 한자리 숫자에 '0'을 더해 문자로 변환한다. 그리고 이 문자를 할당된 공간의 인덱스에 하나씩 넣어준다.

- 변환이 완료되면, 문자열의 마지막에 '\0'을 넣어서 문자열 종료를 알린다. 그다음 문자열의 포인터인 p를 리턴한다.

 

 

 

 

 

(3) ft_strmapi : 기존의 문자열에 함수를 적용한 새로운 문자열 생성

 

 


- 구현 코드 예시 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "libft.h"
 
char        *ft_strmapi(char const *s, char (*f)(unsigned int, char))
{
    char            *str;
    unsigned int    i;
    size_t            len;
 
    len = ft_strlen(s);
    str = malloc(sizeof(char) * (len + 1));
    if (!(str))
        return (0);
    i = 0;
    while (s[i])
    {
        str[i] = (*f)(i, s[i]);
        i++;
    }
    str[i] = '\0';
    return (str);
}
 
Colored by Color Scripter
cs

- 매개변수로 함수의 주소를 받는다.

- malloc()을 통해 매개변수로 받은 문자만큼의 공간을 새로 할당한다.

- 문자열의 모든 문자에 각각 그 함수를 적용하여, 그 결과값으로 나오는 문자들을 새로 할당한 공간에 저장한다.

- 마지막으로, 할당된 공간에 '\0'를 넣어 문자열을 종료시킨다.

- 만들어진 새로운 문자열의 포인터를 리턴한다. 

 

- 주의사항 : malloc() 실패 시 널가드

 

 

저작자표시 (새창열림)

'IT > 42Seoul' 카테고리의 다른 글

TIP : 코드 리뷰 잘 하는 법  (0) 2021.05.24
[Libft] C 언어 라이브러리 구현_Part2_추가함수 구현3  (0) 2021.05.23
[Libft] C 언어 라이브러리 구현_Part2_추가함수 구현1  (0) 2021.05.23
[Libft] C 언어 라이브러리 구현_Part1_malloc을 사용한 함수  (0) 2021.05.20
[Libft] C 언어 라이브러리 구현_Part1_문자 판별 + 변환 관련 함수  (0) 2021.05.20
'IT/42Seoul' 카테고리의 다른 글
  • TIP : 코드 리뷰 잘 하는 법
  • [Libft] C 언어 라이브러리 구현_Part2_추가함수 구현3
  • [Libft] C 언어 라이브러리 구현_Part2_추가함수 구현1
  • [Libft] C 언어 라이브러리 구현_Part1_malloc을 사용한 함수
남서아 (구 - 밥한그릇배따시게)
남서아 (구 - 밥한그릇배따시게)
공부하고 정리한 내용 중, 공유할만한 내용들을 포스팅합니다. / 소프트웨어 학사 (2025년도 2월 졸업)
  • 남서아 (구 - 밥한그릇배따시게)
    SW 개발자 블로그
    남서아 (구 - 밥한그릇배따시게)
  • 전체
    오늘
    어제
  • 공지사항

    • 개발자 정보 및 포트폴리오
    • 포스팅 목적
  • 링크

    • Portfolio
    • 분류 전체보기 (95) N
      • IT (56)
        • CS 공부 (12)
        • 42Seoul (19)
        • 개발 언어 및 도구 (4)
        • 개발 환경 및 설치 (5)
        • 튜토리얼 및 가이드 (9)
        • Data & AI (5)
        • ETC (2)
      • Experience (4)
      • English (32)
        • 회화 (5)
        • 자격증 공부 (26)
        • 후기 (1)
      • 근황 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
남서아 (구 - 밥한그릇배따시게)
[Libft] C 언어 라이브러리 구현_Part2_추가함수 구현2
상단으로

티스토리툴바