> For the complete documentation index, see [llms.txt](https://hidaehyunlee.gitbook.io/fork-my-brain/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hidaehyunlee.gitbook.io/fork-my-brain/c/libft/libft-part-2.md).

# \[Libft] Part 2

libft 프로젝트의 part2 함수들을 구현하면서 메모했던 내용들을 정리해두었다. 이 라이브러리의 함수들은 꾸준히 업데이트 되고 있기 때문에 가장 최신의 코드는 [여기 깃헙저장소](https://github.com/hidaehyunlee/Libft)를 참고...

## **1. ft\_substr**

### **Prototype**

`char *ft_substr(char const *s, unsigned int start, size_t len);`

### **Parameters**

## 1. The string from which to create the substring.

## 2. The start index of the substring in the string ’s’.

## 3. The maximum length of the substring.

### **Return value**

The substring. NULL if the allocation fails.

### **External functs.**

malloc

### **Description**

Allocates (with malloc(3)) and returns a substring from the string ’s’. The substring begins at index ’start’ and is of maximum size ’len’.

### **Source**

```c
    char    *ft_substr(char const *s, unsigned int start, size_t len)
    {
        char *substr;

        if (!s)
            return (NULL);
        if (ft_strlen(s) < start)
            return (ft_strdup(""));
        if (!(substr = (char *)malloc(sizeof(char) * (len + 1))))
            return (NULL);
        ft_strlcpy(substr, s+start, len+1);
        return (substr);
    }
```

* `char const *s`

  s는 문자열이 저장된 메모리의 첫 주소를 저장할 수 있는 포인터 변수

  * 금지되는 것 : 초기화 할 때 한번 지정된 문자열 메모리 주소를 변경할 수 없다.

    예를 들면, `char const *s = "문자열 상수1"` 로 초기화를 했는데,

    `s = "문자열 상수2"` 허용 되지 않음.
* 예외1 : s\[0] 일 때는 return 0;
* 예외2 : s의 길이가 start 주소보다 작을 때는 substr을 만들 수 없으므로

  -> 빈 문자열 반환.
* start 부터 len개 만큼을 복사하면 되니까, ft\_strncpy 혹은 ft\_memmove를 사용할 수 있을 것 같다.

## **2. ft\_strjoin**

### **Prototype**

`char *ft_strjoin(char const *s1, char const *s2);`

### **Parameters**

## 1. The prefix string.

## 2. The suffix string.

### **Return value**

The new string. NULL if the allocation fails.

### **External functs.**

malloc

### **Description**

Allocates (with malloc(3)) and returns a new string, which is the result of the concatenation of ’s1’ and ’s2’.

### **Source**

```c
    #include "libft.h"

    char    *ft_strjoin(char const *s1, char const *s2)
    {
        char *newstr;
        int s1_len;
        int s2_len;

        if (!(s1) && !(s2))
            return (NULL);
        else if (!(s1) || !(s2))
            return (!(s1) ? ft_strdup(s2) : ft_strdup(s1));
        s1_len = ft_strlen(s1);
        s2_len = ft_strlen(s2);
        if (!(newstr = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1))))
            return (NULL);
        ft_strlcpy(newstr, s1, s1_len + 1);
        ft_strlcat(newstr + (s1_len), s2, s2_len + 1);
        return (newstr);
    }
```

* `s == 0;` 과 `s[0] = '\0';`의 차이.
  * char \* s = "" <- 이건 빈문자열
  * char \*s = NULL <- 이건 그냥 s포인터가 가르키는게 없는 것(NULL 인거)
    * s를 리턴 받았을 때,

      전자는 s\[0] == '\0' 이라서 문자열의 끝이 바로 검색되고

      후자는 s\[0] 값 자체를 보려고하면 세그먼트 폴트가 뜬다.

## **3. ft\_strtrim**

### **Prototype char**

`*ft_strtrim(char const *s1, char const *set);`

### **Parameters**

## 1. The string to be trimmed.

## 2. The reference set of characters to trim.

### **Return value**

The trimmed string. NULL if the allocation fails.

### **External functs.**

malloc

### **Description**

Allocates (with malloc(3)) and returns a copy of ’s1’ with the characters specified in ’set’ removed from the beginning and the end of the string

### **Source**

```c
    #include "libft.h"

    int         ft_getstart(const char *s1, const char *set)
    {
        size_t  len;
        size_t  i;

        len = ft_strlen(s1);
        i = 0;
        while (i < len)
        {
            if (ft_strchr(set, s1[i]) == 0)
                break ;
            i++;
        }
        return (i);
    }

    int         ft_getend(const char *s1, const char *set)
    {
        size_t  len;
        size_t  i;

        len = ft_strlen(s1);
        i = 0;
        while (i < len)
        {
            if (ft_strchr(set, s1[len - i - 1]) == 0)
                break ;
            i++;
        }
        return (len - i);
    }

    char        *ft_strtrim(char const *s1, char const *set)
    { 
        int     start;
        int     end;
        char    *newstr;

        if (s1 == NULL)
            return (NULL);
        if (set == NULL)
            return (ft_strdup(s1));
        start = ft_getstart(s1, set);
        end = ft_getend(s1, set);
        if (start >= end)
            return (ft_strdup(""));
        newstr = (char *)malloc(sizeof(char) * (end - start + 1) + 1);
        if (newstr == NULL)
            return (NULL);
        ft_strlcpy(newstr, s1 + start, end - start + 1);
        return(newstr);
    }

    exemple :

    1) s1 = "ABCCBA"   set = "AB"
    résultat : "CC"
    2) s1 = "ACCBACBA" set = "AB"
    résultat : "CCBAC"
    3) s1 = "Hello World!"  set = "Hlde"
    résultat : "o World!"
```

* s1의 앞뒤로 set에 들어간 문자는 모두 삭제한 뒤 반환하는 함수
* 앞 뒤 공백을 자를 때 유용할 것 같다.
* 다 구현하고 보니 ft\_strsub 함수를 이용했으면 4줄 이상을 줄일 수 있었던 것 같다. 나중에 바꿔봐야지.
* if (start >= end) → return (ft\_strdup(""));

## **4. ft\_split**

### **Prototype**

`char **ft_split(char const *s, char c);`

### **Parameters**

## 1. The string to be split.

## 2. The delimiter character.

### **Return value**

The array of new strings resulting from the split. NULL if the allocation fails.

### **External functs.**

malloc, free

### **Description**

Allocates (with malloc(3)) and returns an array of strings obtained by splitting ’s’ using the character ’c’ as a delimiter. The array must be ended by a NULL pointer

### **Source**

```c
    #include "libft.h"

    static char            **ft_malloc_error(char **tab)
    {
        unsigned int    i;

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

    static unsigned int    ft_get_nb_strs(char const *s, char c)
    {
        unsigned int    i;
        unsigned int    nb_strs;

        if (!s[0])
            return (0);
        i = 0;
        nb_strs = 0;
        while (s[i] && s[i] == c) //c가 제일 앞에, 여러 개 연속으로 있을 때 패스
            i++;
        while (s[i])
        {
            if (s[i] == c)
            {
                nb_strs++;
                while (s[i] && s[i] == c)
                    i++;
                continue ;
            }
            i++;
        }
        if (s[i - 1] != c)
            nb_strs++; //마지막이 c로 안 끝났으면 +1
        return (nb_strs);
    }

    static void            ft_get_next_str(char **next_str, unsigned int *next_str_len,
                        char c)
    {
        unsigned int i;

        *next_str += *next_str_len; //실제 next_str 주소 ++
        *next_str_len = 0;
        i = 0;
        while (**next_str && **next_str == c)
            (*next_str)++;
        while ((*next_str)[i]) //갯수 샐 때는 지역변수 i 이용
        {
            if ((*next_str)[i] == c)
                return ;
            (*next_str_len)++;
            i++;
        }
    }

    char                **ft_split(char const *s, char c)
    {
        char            **tab;
        char            *next_str;
        unsigned int    next_str_len;
        unsigned int    nb_strs;
        unsigned int    i;

        if (!s)
            return (NULL);
        nb_strs = ft_get_nb_strs(s, c);
        if (!(tab = (char **)malloc(sizeof(char *) * (nb_strs + 1)))) //마지막 tab[i]에도 NULL보장
            return (NULL);
        i = 0;
        next_str = (char *)s;
        next_str_len = 0;
        while (i < nb_strs)
        {
            ft_get_next_str(&next_str, &next_str_len, c);
            if (!(tab[i] = (char *)malloc(sizeof(char) * (next_str_len + 1))))
                return (ft_malloc_error(tab));
            ft_strlcpy(tab[i], next_str, next_str_len + 1);
            i++;
        }
        tab[i] = NULL;
        return (tab);
    }

    int                main(void)
    {
        char    **tab;
        unsigned int    i;

        i = 0;
        tab = ft_split("sdsdsdasd", ' ');
        while (tab[i] != NULL)
        {
            printf("%s\n", tab[i]);
            i++;
        }
    }
```

* 너무 어려워서 다른 분의 코드를 참고했다.
* 정적 함수

  정적 함수를 사용하셔서 조금 찾아봤는데, 정적 함수를 사용하게 되면 이 파일 안에서만 사용할 수 있는 함수가 된다. 다른 파일에 같은 이름의 함수가 있어도 충돌하지 않는다.

  참고 : <https://dojang.io/mod/page/view.php?id=691>

## **5. ft\_itoa**

### **Prototype**

`char *ft_itoa(int n);`

### **Parameters**

## 1. the integer to convert.

### **Return value**

The string representing the integer. NULL if the allocation fails.

### **External functs.**

malloc

### **Description**

Allocates (with malloc(3)) and returns a string representing the integer received as an argument. Negative numbers must be handled.

### **Source**

```c
    #include "libft.h"

    long int        ft_abs(long int nbr)
    {
        return ((nbr < 0) ? -nbr : nbr);
    }

    int                ft_len(long int nbr)
    {
        int        len;

        len = (nbr <= 0) ? 1 : 0;
        while (nbr != 0)
        {
            nbr = nbr / 10;
            len++;
        }
        return (len);
    }

    char            *ft_itoa(int n)
    {
        int            len;
        int            sign;
        char        *c;

        sign = (n < 0) ? -1 : 1;
        len = ft_len(n);
        c = (char *)malloc(sizeof(char) * len + 1);
        c[len] = '\0';
        len--;
        while (len >= 0)
        {
            c[len] = '0' + ft_abs(n % 10);
            n = ft_abs(n / 10);
            len--;
        }
        if (sign == -1)
            c[0] = '-';
        return (c);
    }
```

* `'0' + (n % 10)` 식으로 나머지를 구한 뒤 문자 아스키코드로 변환해 배열의 뒷 부분 부터 채워준다. 이때 아스키코드 상으로 음수를 표현할 수는 없으니 절대값 함수를 사용해준다.
* 정수의 길이를 잴 때는 몫 나머지 연산을 사용한다. 몫이 0이 될 때 까지. 그리고 음수일 경우에는 '-' 부호가 들어가야하기 때문에 len에 +1 을 해준다.

## **6. ft\_strmapi**

### **Prototype**

`char *ft_strmapi(char const *s, char (*f)(unsigned int, char));`

### **Parameters**

## 1. The string on which to iterate.

## 2. The function to apply to each character.

### **Return value**

The string created from the successive applications of ’f’. Returns NULL if the allocation fails.

### **External functs.**

malloc

### **Description**

Applies the function ’f’ to each character of the string ’s’ to create a new string (with malloc(3)) resulting from successive applications of ’f’.

### **Source**

```c
    #include "libft.h"

    char    *ft_strmapi(char const *s, char (*f)(unsigned int, char))
    {
        char *newstr;
        unsigned int len;
        unsigned int i;

        if (s == 0 || f == 0)
            return (NULL);
        len = ft_strlen(s);
        if (!(newstr = (char *)malloc(sizeof(char)*(len + 1))))
            return (NULL);
        i = 0;
        while (s[i])
        {
            newstr[i] = f(i, s[i]);
            i++;
        }
        newstr[i] = '\0';
        return (newstr);
    }

    char f(unsigned int i, char c)
    {
        if (i+1)
        {
            if (ft_isalpha(c))
                c = c - 32;
        }
        return (c);
    }

    int     main(void)
    {
        char *s = "hi daehyun lee";
        printf("%s\n", ft_strmapi(s, f));
        return 0;
    }
```

* **함수 포인터**
  * 반환값자료형 (\*함수포인터이름)();
  * 함수 포인터를 선언할 때는 함수 포인터와 저장될 함수의 반환값 자료형, 매개변수 자료형과 개수가 일치해야 한다.

    ```c
          #include <stdio.h>

          void hello()
          {
              printf("Hello, world!\n");
          }

          void bonjour()
          {
              printf("bonjour le monde!\n");
          }

          int main()
          {
              void (*fp)();   // 반환값과 매개변수가 없는 함수 포인터 fp 선언

              fp = hello;     // hello 함수의 메모리 주소를 함수 포인터 fp에 저장
              fp();           // Hello, world!

              fp = bonjour;   // bonjour 함수의 메모리 주소를 함수 포인터 fp에 저장
              fp();           // bonjour le monde!

              return 0;
          }
    ```
  * fp에는 hello 함수 대신 bonjour 함수를 넣어서 호출해도 된다.
  * *즉, 함수 포인터를 사용하면 함수를 전구 소켓처럼 갈아 끼울 수 있다....*
  * 참고 : <https://dojang.io/mod/page/view.php?id=592>

## **7. ft\_putchar\_fd**

### **Prototype**

`void ft_putchar_fd(char c, int fd);`

### **Parameters**

## 1. The character to output.

## 2. The file descriptor on which to write.

### **Return value**

None

### **External functs.**

write

### **Description**

Outputs the character ’c’ to the given file descriptor.

### **Source**

```c
    #include "libft.h"

    void    ft_putchar_fd(char c, int fd)
    {
        if (fd < 0)
            return ;
        write(fd, &c, 1);
    }
```

* void 함수에 return ?

  open() 함수는 다음과 같이 사용하기 때문에, `fd=open("data.txt", O_RDONLY)` 파일 오픈에 실패하면 file descriptor는 음수값을 갖게 된다.

  이 때 '함수의 종결'을 의미하는 `return ;` 사용한다.
* **include \<linux/fs.h>**

  write() 함수를 사용하려면 이 헤더파일을 인클루드 해야한다.

## **8. ft\_putstr\_fd**

### **Prototype**

`void ft_putstr_fd(char *s, int fd);`

### **Parameters**

## 1. The string to output.

## 2. The file descriptor on which to write.

### **External functs.**

write

### **Description**

Outputs the string ’s’ to the given file descriptor.

### **Source**

```c
    #include "libft.h"

    void    ft_putstr_fd(char *s, int fd)
    {
        if (!(s) || fd < 0)
            return ;
        write(fd, s, ft_strlen(s));
    }
```

## **9. ft\_putendl\_fd**

### **Prototype**

`void ft_putendl_fd(char *s, int fd);`

### **Parameters**

## 1. The string to output.

## 2. The file descriptor on which to write.

### **External functs.**

write

### **Description**

Outputs the string ’s’ to the given file descriptor, followed by a newline.

### **Source**

```c
    #include "libft.h"

    void    ft_putendl_fd(char *s, int fd)
    {
        if (!(s) || fd < 0)
            return ;
        write(fd, s, ft_strlen(s));
        write(fd, "\n", 1);
    }
```

## **10. ft\_putnbr\_fd**

### **Prototype**

`void ft_putnbr_fd(int n, int fd);`

### **Parameters**

## 1. The integer to output.

## 2. The file descriptor on which to write.

### **External functs.**

write

### **Description**

Outputs the integer ’n’ to the given file descriptor.

### **Source**

```c
    #include "libft.h"

    void    display_nbr(int n, int fd)
    {
        if (n >= 10)
            display_nbr(n / 10, fd);
        write(fd, &"0123456789"[n % 10], 1);
    }

    void    ft_putnbr_fd(int n, int fd)
    {
        if (fd < 0)
            return ;
        if (n == -2147483648)
        {
            write(fd, "-2147483648", 11);
            return ;
        }
        if (n < 0)
        {
            write(fd, "-", 1);
            n *= -1;
        }
        display_nbr(n, fd);
    }
```

* 난 지금까지 display\_nbr 함수를 만들 때 아래 코드처럼 배열을 하나 만들어 출력했었는데, write함수 인자에 바로 문자열의 주소를 넣어버리는 방법도 있었다. 3줄 절약 가능.

  ```c
    void    display_nbr(int n, int fd)
    {
        char *decimal;

        decimal = "0123456789";
        if (n >= 10)
            display_nbr(n / 10, fd);
        write(fd, decimal + (n % 10), 1);
    }
  ```
