[42 seoul] libft

한종민·2023년 4월 1일
0

42SEOUL

목록 보기
2/6

libft


part1

  • isalpha
  • isascii
  • memset
  • memmove
  • strncmp
  • strrchr
  • strnstr
  • strdup
  • isdigit
  • isprint
  • bzero
  • strlcpy
  • toupper
  • memchr
  • atoi
  • memcmp
  • isalnum
  • strlen
  • memcpy
  • strlcat
  • tolower
  • strchr
  • calloc

part2

  • ft_substr
  • ft_split
  • ft_striteri
  • ft_putendl_fd
  • ft_strjoin
  • ft_itoa
  • ft_putchar_fd
  • ft_putnbr_fd
  • ft_strtrim
  • ft_strmapi
  • ft_putstr_fd

BONUS

  • ft_lstmap
  • ft_lstadd
  • ft_lstclear
  • ft_lstdelone
  • ft_lstlast
  • ft_lstiter
  • ft_lstsize
  • ft_lstnew

Tip!

Const 키워드란

constant의 약자로 “변함없는” 이란 뜻으로 변수 앞에 붙이면 값을 변경하지 못하도록 한다. 해당 변수를 상수로 취급하게 된다.

메모리 누수란

동적으로 할당한 메모리가 free될 수 없 는 상태가 된것.

발생시 문제점 : 누수가 지속적으로 일어날 경우 메모리 사용량이 증가되고, 결국 시스템의 메모리가 부족해져 운영체제가 프로그램을 강제로 종료시키거나 메모리 할당에 실패할 수 있다.

make re

re fclean all의 경우 순서가 뒤바뀌는 경우가 있을수 있다.

연결리스트 구현시 이중 포인터를 사용하는 이유

단일 연결 리스트에서 삽입과 삭제를 통해 head 포인터의 값을 변화시킬 수 있다.

이때, 호출 함수의 포인터 변수가 참조하는 객체를 피호출 함수에서 바꾸고자 할 경우 이중 포인터를 사용하면 된다.

t_list **lst는 t_list포인터의 주소를 가리키는 값

t_list *lst 변수가 담고 있는 값은 t_list 의 주소

t_list lst변수가 담고 있는 겂은 어떤 리스트의 첫번째 주소 즉, lst는 head의 주소

*lst == null은 빈 리스트

lst == null은 리스트 자체가 존재하지 않는다는 것.

ft_atoi

ascii to int 함수

맨 앞의 공백문자는 스킵함, 부호는 하나만 있어야함. 중간에 '0' ~ '9' 외의 문자가 있으면 멈춤.

atoi의 반환값은 (int)strtol(str, (char **)NULL, 10); 와 같다.

--> long 범위에서 int형 범위를 벗어난 경우, 오버플로된 값을 그대로 리턴

--> long 범위를 벗어난 경우, 음수일 땐 0 양수일 땐 -1을 리턴함. (이 부분은 구현을 해야하는 가에 대해서 많은 말들이 있었다. 기존의 atoi함수를 완벽하게 구현해야 한다면, 구현하는게 맞다고 생각했지만, 이번 과제는 내가 사용할 함수들을 직접! 구현하는 과제라고 생각해 int범위까지만 변환될 수 있게만 해도 무방할 것이라 생각했다.)

(❗️맥에서는 long범위와 longlong의 범위가 같다.)

int	ft_atoi(const char *str)
{
	int	index;
	int	sign;
	int	num;

	index = 0;
	sign = 1;
	num = 0;
	while ((str[index] >= 9 && str[index] <= 13) || str[index] == 32)
		index++;
	if (str[index] == '+' || str[index] == '-')
	{
		if (str[index] == '-')
			sign = -1;
		index++;
	}
	while (str[index] >= '0' && str[index] <= '9')
	{
			num = num * 10 + (str[index] - '0');
			index++;
	}
	return (sign * num);
}

/*
#include <stdio.h>

int main(void)
{
    printf("a int max 2147483647 : %d\n", atoi("2147483647"));
    printf("f int max 2147483647 : %d\n", ft_atoi("2147483647"));
    printf("a int min -2147483648 : %d\n", atoi("-2147483648"));
    printf("f int min -2147483648 : %d\n", ft_atoi("-2147483648"));
    printf("a int over 9999999999 : %d\n", atoi("9999999999"));
    printf("f int over 9999999999 : %d\n", ft_atoi("9999999999"));
    printf("a int under -9999999999 : %d\n", atoi("-9999999999"));
    printf("f int under -9999999999 : %d\n", ft_atoi("-9999999999"));
    printf("a long long plus 92233720368547758 : %d\n", atoi("92233720368547758"));
    printf("f long long plus 92233720368547758 : %d\n", ft_atoi("92233720368547758"));
    printf("a long long minus -92233720368547758 : %d\n", atoi("-92233720368547758"));
    printf("f long long minus -92233720368547758 : %d\n", ft_atoi("-92233720368547758"));
    printf("a long long max 9223372036854775807 : %d\n", atoi("9223372036854775807"));
    printf("f long long max 9223372036854775807 : %d\n", ft_atoi("9223372036854775807"));
    printf("a long long min -9223372036854775808 : %d\n", atoi("–9223372036854775808"));
    printf("f long long min -9223372036854775808 : %d\n", ft_atoi("–9223372036854775808"));
    printf("a long long max / 10 922337203685477580 : %d\n", atoi("922337203685477580"));
    printf("f long long max / 10 922337203685477580 : %d\n", ft_atoi("922337203685477580"));
    printf("a long long max / 10 + 1 922337203685477581 : %d\n", atoi("922337203685477581"));
    printf("f long long max / 10 + 1 922337203685477581 : %d\n", ft_atoi("922337203685477581"));
    printf("a long long max / 10 + 4 922337203685477584 : %d\n", atoi("922337203685477584"));
    printf("f long long max / 10 + 4 922337203685477584 : %d\n", ft_atoi("922337203685477584"));
    printf("a long long max / 10 + 5 922337203685477585 : %d\n", atoi("922337203685477585"));
    printf("f long long max / 10 + 5 922337203685477585 : %d\n", ft_atoi("922337203685477585"));
    printf("a long long max - 1 922337203685477586 : %d\n", atoi("922337203685477586"));
    printf("f long long max - 1 922337203685477586 : %d\n", ft_atoi("922337203685477586"));
    printf("a long long max + 1 9223372036854775808 : %d\n", atoi("9223372036854775808"));
    printf("f long long max + 1 9223372036854775808 : %d\n", ft_atoi("9223372036854775808"));
    printf("a long long max + 2 9223372036854775809 : %d\n", atoi("9223372036854775809"));
    printf("f long long max + 2 9223372036854775809 : %d\n", ft_atoi("9223372036854775809"));
    printf("a long long max + 10 9223372036854775817 : %d\n", atoi("9223372036854775817"));
    printf("f long long max + 10 9223372036854775817 : %d\n", ft_atoi("9223372036854775817"));
    printf("a long long min - 1 –9223372036854775809 : %d\n", atoi("–9223372036854775809"));
    printf("f long long min - 1 –9223372036854775809 : %d\n", ft_atoi("–9223372036854775809"));
    printf("a long long min - 2 –9223372036854775810 : %d\n", atoi("–9223372036854775810"));
    printf("f long long min - 2 –9223372036854775810 : %d\n", ft_atoi("–9223372036854775810"));
    printf("a long long min - 10 –9223372036854775818 : %d\n", atoi("–9223372036854775818"));
    printf("f long long min - 10 –9223372036854775818 : %d\n", ft_atoi("–9223372036854775818"));
    printf("a long long over 9223379876854775807 : %d\n", atoi("9223379876854775807"));
    printf("f long long over 9223379876854775807 : %d\n", ft_atoi("9223379876854775807"));
    printf("a long long under -9223379876854775807 : %d\n", atoi("-9223379876854775807"));
    printf("f long long under -9223379876854775807 : %d\n", ft_atoi("-9223379876854775807"));
    printf("a long long half 4611686018427387903 : %d\n", atoi("4611686018427387903"));
    printf("f long long half 4611686018427387903 : %d\n", ft_atoi("4611686018427387903"));
    printf("a zero 0 : %d\n", atoi("0"));
    printf("f zero 0 : %d\n", ft_atoi("0"));
    printf("a empty  : %d\n", atoi(""));
    printf("f empty  : %d\n", ft_atoi(""));
    return (0);
}*/

ft_bzero

  • 인자 s : 초기화를 진행할 포인터이다.
  • 인자 n : s에서부터 n byte 만큼 초기화를 진행한다.

포인터 s부터 값을 n byte만큼 0 으로 초기화 해 주는 함수이다. s는 함수 내에서 unsigned char의 형태로 캐스팅 되어 사용된다.

#include "libft.h"

void	ft_bzero(void *s, size_t n)
{
	size_t			i;
	unsigned char	*p;

	p = (unsigned char *)s;
	i = 0;
	while (i < n)
		p[i++] = 0;
}

ft_calloc

size바이트 크기의 변수를 count 개 저장할수 있는 크기를 할당하고 0으로 초기화

return value : 성공시 할당된 메모리의 포인터, 실패시 NULL

#include "libft.h"

void	*ft_calloc(size_t count, size_t size)
{
	unsigned char	*p;
	size_t			i;

	p = (unsigned char *)malloc(sizeof(char) * (count * size));
	if (p == 0)
		return (0);
	i = 0;
	while (i < size * count)
	{
		p[i++] = 0;
	}
	return ((void *)p);
}

#include "libft.h"

void	*ft_calloc(size_t count, size_t size)
{
	unsigned char	*p;
	size_t			i;

	p = (unsigned char *)malloc(sizeof(char) * (count * size));
	if (p == 0)
		return (0);
	i = 0;
	while (i < size * count)
	{
		p[i++] = 0;
	}
	return ((void *)p);
}

ft_isalnum

int isalnum( int _C );

_C가 알파벳이거나 숫자인지를 판별하게 됩니다.

알파벳이거나 숫자이면 0이 아닌 값을 리턴합니다. 알파벳이거나 숫자가 아니면 0을 리턴합니다.

int	ft_isalnum(int c)
{
	if (c >= 60 && c <= 71)
		return (1);
	else if (c >= 101 && c <= 132)
		return (1);
	else if (c >= 141 && c <= 172)
		return (1);
	else
		return (0);
}

ft_isalpha

int isalpha(int c);

_C가 소문자 알파벳인지 대문자 알파벳인지를 판별하게 됩니다.

매개변수 : C언어에서 아스키 코드에 해당하는 문자들은 숫자로 표현이 되고, 문자를 넣으면 자동으로 아스키 코드에 있는 숫자로 들어가기 때문에 int 타입이긴 하지만 'a', 'A', '1' 등을 집어 넣어도됩니다.즉, 'a' 와 같이 char 타입으로 집어 넣어도 자동으로 int 타입으로 형변환 되어서 들어가게 됩니다. 아스키 코드 표를 참고하면 'a'는 자동으로 숫자 97로 형변환되어 들어가게 됩니다.

반환형 : 알파벳일 경우 1, 아닐 경우 0을 반환합니다.

int	ft_isalpha(int c)
{
	if (c >= 'A' && c <= 'Z')
		return (1);
	else if (c >= 'a' && c <= 'z')
		return (1);
	else
		return (0);
}

ft_isascii

아스키에 포함 여부 판별 함수

int	ft_isascii(int c)
{
	if (c >= 0 && c <= 127)
		return (1);
	return (0);
}

ft_isdigit

숫자인지 판별해주는 함수

int	ft_isdigit(int c)
{
	if (c >= '0' && c <= '9')
		return (1);
	return (0);
}

ft_isprint

printable 한지 판별해주는 함수

int	ft_isprint(int c)
{
	if (c >= 32 && c <= 126)
		return (1);
	return (0);
}

ft_itoa

int형 숫자를 문자형 ascii로 변환하는 함수

아래의 코드는 음수인 n이 들어왓을 때 양수로 바꾸어 준 뒤 진행되는데, 이러한 경우 INT_MIN이 들어왓을 경우 양수로 바꾸어 주었을 때,

#include "libft.h"
#include <stdio.h>

static int	detec_len(long long nbr)
{
	int	len;

	len = 0;
	if (nbr < 0)
	{
		nbr *= -1;
		len++;
	}
	while (nbr >= 10)
	{
		nbr = nbr / 10;
		len++;
	}
	len++;
	return (len);
}

char	*ft_itoa(int n)
{
	long long	nbr;
	int			len;
	char		*arr;

	nbr = (long long)n;
	len = detec_len(nbr);
	arr = (char *)malloc(sizeof(char) * (len + 1));
	if (!arr)
		return (NULL);
	if (nbr < 0)
	{
		nbr *= -1;
		arr[0] = '-';
	}
	if (nbr == 0)
		arr[0] = '0';
	arr[len] = '\0';
	while (nbr != 0)
	{
		arr[len - 1] = (nbr % 10) + '0';
		nbr /= 10;
		len--;
	}
	return (arr);
}
/*
int main(void)
{
	printf("%s", ft_itoa(123123123123123123123123123123123));
}
*/

ft_memchr

void *memchr(const void *s, int c, size_t n);

s에서 n바이트 중에서 c를 찾는 함수.

  • s : 검색을 수행하는 시작 주소
  • c : 검색 문자
  • n : 검색을 시작한 부분부터 검색을 수행할 만큼의 바이트 수

Return value : 처음 발견된 위치의 포인터, 발견하지 못하면 NULL

unsigned char로 캐스팅 하는 이유

  • C표준 명세에서 unsigned char 형만 보증하고 있고
  • padding 문제가 발생하지 않으며
  • -0 을 null로 인식하는 문제에서 자유롭기 때문
  • 1바이트씩 접근하기 위함
#include "libft.h"

void	*ft_memchr(const void *s, int c, size_t n)
{
	unsigned char	*p;
	size_t			i;

	p = (unsigned char *)s;
	i = 0;
	while (i < n)
	{
		if (p[i] == (unsigned char *)c)
			return ((void *)s[i]);
		i++;
	}
	return (0);
}

ft_memcmp

두 개의 메모리 블럭을 비교

int	ft_memcmp(const void *s1, const void *s2, size_t n)
{
	unsigned char	*str1;
	unsigned char	*str2;
	size_t			i;

	i = 0;
	if (n == 0)
		return (0);
	str1 = (unsigned char *)s1;
	str2 = (unsigned char *)s2;
	while (i < n)
	{
		if (str1[i] != str2[i])
			return (str1[i] - str2[i]);
		i++;
	}
	return (0);
}

ft_memcpy

Src가 가리키는 곳 부터 Size 바이트 만큼 Dst이 가리키는 곳으로 복사

메모리 영역 src로부터 n바이트를 메모리 영역 dst에 복사한다.

dst와 src의 메모리 공간이 겹쳐져 있는 경우는 undefined. behavior이다.

겹쳐져 있는 경우 memmove()를 사용.!


  1. Memset, memcpy 등의 함수는 이름과 같이 메모리의 정보 그대로를 복사하는 함수입니다. 그 메모리가 나타내는 값(value)을 복사하는 게 아니라 메모리의 비트열을 그대로 복사하는 것이 목적인 굉장히 저수준(low-level)의 목적을 가진 함수이죠. C 명세서에서는 이런 오브젝트의 비트열을 object representation 이라고 합니다. C에서의 오브젝트란 할당된 공간에 유의미한 값이 들어있는 것입니다. 쉽게 보면 변수를 메모리적인 관점에서 본 것이라고 이해해도 될 것 같습니다. 이제 메모리의 데이터를 복사하는 것이란 이 object representation을 복사하는 것이라는 것을 알 수 있습니다. Object representation이 곧 메모리의 비트열이기 때문이죠. 그런데 c명세서에서 object representation을 정의할 때 이렇게 정의하고 있습니다. "모든 n바이트의 객체는 unsigned char[n] 형태의 메모리에 복사 가능헤야 하며 이 때 그 비트열을 object representation이라고 정의한다". 이렇듯 그 정의 자체가 unsigned char에 의존하기 때문에 메모리 관련 함수에는 unsigned char를 사용합니다.
  2. C언어 명세서에서 바이트가 항상 8비트를 의미하지는 않습니다. C언어에서 바이트와 char는 서로 비교하기 좋으니 같이 이야기하겠습니다. 우선 명세 상 바이트는 "addressable unit 이며 시스템의 default character set을 저장할 수 있어야 한다" 라고 정의되며, 자료형의 char타입을 설명한 절에서 char는 "시스템의 default characrer set을 저장할 수 있어야 하며 그 동작은 signed char 혹은 unsigned char와 동일해야 한다. 다만 그 선택은 컴파일러 구현체의 자유이다" 라고 정의됩니다. 여기에서 바이트가 꼭 8비트여야 하는 것이 아니라 default character set을 저장할 수 있으며 addressable unit이기만 하면 된다는 것을 알 수 있습니다. 그리고 char는 거의 동일한 정의에서 addressable unit만 빠져있다는 것도 알 수 있죠. 이제 중간과정을 조금 생략해서, 명세서에 "바이트와 char는 동일하다" 라는 명시적 언급은 없지만 여러 조항들을 종합해보면 바이트와 char는 같은 사이즈임을 추론할 수 있습니다. 결국 char가 16비트인 시스템에서는 16비트가 1바이트가 되는 것이죠.
  3. 다시 이어서 바이트와 char에 대한 이야기를 이어가자면, c언어 명세서에는 CHAR_BIT 라는 것을 정의하는데요, 이름대로 char 의 크기를 비트수로 나타낸 것입니다. Char가 8비크라면 CHAR_BIT는 8이 되고 CHAR가 16비트라면 CHAR_BIT는 16이 되는 식이지요. 그리고 C 명세 상 바이트가 CHAR_BIT와 동일하다는 명시적 언급은 없는 것으로 알고 있는데 여러 조항들을 조합하면 결국 바이트의 크기가 CHAR_BIT와 동일하다는 결론을 추론할 수 있다고 합니다. 그리고 CHAR_BIT 의 예시를 8비트로 서술하며 "모든 구현체에서 CHAR_BIT의 크기는 이보다 커야 한다" 라고 기술하고 있습니다. 이 부분이 우리가 흔히 알고 있는 "char 형은 크기가 8비트 이상이어야 한다" 라는 주장의 근거로 쓰이는 명세입니다.
  4. 추가로 재밌는 것이 위의 char와 마찬가지로 모든 자료형이 보장해야 하는 최소범위에 대한 명세는 자료형을 설명하는 장에 없습니다. <limits.h> 를 정의하는 절에서 CHAR_MAX, INT_MIN 등을 정의하면서 숫자도 하나씩 같이 써 주고 "모든 컴파일러 구현체들은 이 수의 절대값보다 큰 수로 limits.h의 매크로들을 정의해야 한다" 라고 기술함으로써 각 자료형의 최소범위를 정의합니다.
  5. C언어의 공식 명세서는 유료이며 저작권으로 보호받기에 인터넷에서 구할 수 없습니다. 하지만 공식 명세서로 출판되기 전의 수정 단계에 있는 draft 버전을 무료로 공개해 줍니다. 인터넷에서 보는 대부분의 c 명세서는 이 draft버전일 겁니다. 제가 쓴 글도 c99의 draft를 기반으로 하고 있습니다. C11에서는 변경된 내용이 있을 수도 있습니다. 그래도 최종 draft는 거의 확정되기 직전 단계이기 때문에 최종 표준안과 크게 다른 부분은 앖을 겁니다. 그래서 대부분의 스택오버플로우 답변, 위키피디아 등에서도 draft를 출처로 사용합니다.

void *memcpy(void *Dst,const void *Src,size_t Size)
#include "libft.h"

void	*ft_memcpy(void *dst, const void *src, size_t n)
{
	size_t			i;
	unsigned char	*c_dst;
	unsigned char	*c_src;

	i = 0;
	c_dst = (unsigned char *)dst;
	c_src = (unsigned char *)src;
	if (c_dst == c_src)
		return (c_dst);
	while (i < n)
	{
		c_dst[i] = c_src[i];
		i++;
	}
	return (dst);
}

ft_memmove

dest의 주소가 src보다 뒤에 있을 경우 문제가 발생하기 때문에 별도의 처리가 필요

→ 이 경우 뒤에서 부터 복사 진행

#include "libft.h"

void	*ft_memmove(void *dest, const void *src, size_t num)
{
	size_t			i;

	i = 0;
	if (!(unsigned char *)dest && !(unsigned char *)src)
		return (dest);
	if ((unsigned char *)dest >= (unsigned char *)src)
	{
		while (i < num)
		{
			((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
			i++;
		}
	}
	else if ((unsigned char *)dest < (unsigned char *)src)
	{
		while (i < num)
		{
			((unsigned char *)dest)[num - 1 - i] =
			((unsigned char *)src)[num - 1 - i];
			i++;
		}
	}
	return (dest);
}

ft_memset

len 바이트 만큼 b주소에 c를 복사

#include "libft.h"

void	*ft_memset(void *b, int c, size_t len)
{
	unsigned char	*p;
	size_t			i;

	set = (unsigned char)c;
	p = (unsigned char *)b;
	i = 0;
	while (i < len)
		p[i++] = set;
	return (b);
}

ft_ tolower

int tolower(int c)

c가 알파벳 대문자인 경우 소문자로 바꿔서 리턴

int	ft_tolower(int c)
{
	if ('A' <= c && c >= 'Z')
		return (c + 32);
	return (c);
}

ft_toupper

int toupper(int c)

c가 알파벳 소문자인 경우 대문자로 바꿔서 리턴

int	ft_toupper(int c)
{
	if ('a' <= c && c >= 'z')
		return (c - 32);
	return (c);
}

ft_strlen

문자열의 길이를 반환해주는 함수

size_t	ft_strlen(const char *str)
{
	size_t	a;

	a = 0;
	while (str[a] != '\0')
		a++;
	return (a);
}

ft_strchr

문장에서 문자 찾기

ft_strrchr

문장에서 뒤에서부터 문자 찾기

#include "libft.h"

char	*ft_strrchr(const char *s, int c)
{
	int	i;

	i = ft_strlen(s);
	while (i >= 0)
	{
		if (s[i] == (unsigned char)c)
			return ((char *)s + i);
		i--;
	}
	return (0);
}

ft_strnstr

문장에의 n 범위내에서 str찾기

needle이 빈 문자열이면 haystack의 첫 주소가 반환.

못 찾을 경우 NULL리턴

#include "libft.h"

char	*ft_strnstr(const char *haystack, const char *needle, size_t len)
{
	size_t	i;
	size_t	j;

	j = 0;
	i = 0;
	if (*needle == '\0')
		return ((char *)haystack);
	while (i < len && haystack[i] != '\0')
	{
		if (haystack[i] == needle[0])
		{
			j = 1;
			while (needle[j] != '\0' && i + j < len
				&& haystack[i + j] == needle[j])
			j++;
			if (needle[j] == '\0')
				return ((char *)&haystack[i]);
		}
		i++;
	}
	return (NULL);
}

/*#include <stdio.h>

int main()
{
	const char s1[] = "hello";
	const char s2[] = "el";
	char *str;

	str = ft_strnstr(s1, s2, 3);
	printf("%s",str);
}*/

ft_substr

문자열을 자를때 사용하는 함수

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

s: 부분 문자열 (substring) 을 생성할 원본 문자열

start: 부분 문자열의 맨 처음 인덱스

len: 부분 문자열의 최대 길이

Return Value

부분 문자열. 할당 실패 시, NULL

char	*ft_substr(char const *s, unsigned int start, size_t len)
{
	size_t	i;
	size_t	j;
	char	*sub;

	i = 0;
	j = 0;
	if (!s)
		return (NULL);
	if (!(sub = (char *)malloc(sizeof(char) * (len + 1))))
		return (NULL);
	while (s[i])
	{
		if (i >= start && j < len)
		{
			sub[j] = s[i];
			j++;
		}
		i++;
	}
	sub[j] = '\0';
	return (sub);
}
## MKO가 발생하는 코드

문자열의 끝을 확인하지 않음: 
문자열 s가 null 종료되어있는지 확인하지 않고 while 루프를 사용하여 문자열을 반복하므로 s가 null 
종료되어 있지 않으면 예기치 않은 결과가 발생할 수 있습니다.

할당된 메모리의 해제: 
이 코드는 메모리를 동적으로 할당하고 있지만 할당된 메모리를 해제하지 않습니다. 
이는 메모리 누수(memory leak)를 발생시킬 수 있으며 장기적으로는 시스템에 부정적인 영향을 미칠 수 
있습니다.

문자열 길이 검사: 
문자열 s의 길이를 검사하지 않으므로, start 매개변수가 s의 길이보다 크거나 같은 경우, 
해당 함수는 빈 문자열을 반환합니다. 따라서 문자열 s의 길이를 검사하여 해당 문자열이 start 인덱스보다 
길지 않은 경우 이를 처리해야 합니다.

마지막 문자열 문자 포함: 
반환되는 하위 문자열(substring)에 null 종료 문자('\0')가 포함되지 않는 문제가 있습니다. 
이것은 문자열 함수를 사용하여 하위 문자열을 사용할 때 예기치 않은 결과를 초래할 수 있습니다.

부호 없는 정수와 부호 있는 정수의 혼용: 
start 매개변수는 부호 없는 정수(unsigned int)로 선언되어 있지만 i 변수는 size_t형으로 선언되어 
있으므로 부호 없는 정수와 부호 있는 정수의 혼용이 발생합니다. 이는 컴파일러에 따라 다른 동작을 할 수 
있으므로 이 문제를 수정해야 합니다.
#include "libft.h"

char	*ft_substr(char const *s, unsigned int start, size_t len)
{
	size_t	i;
	size_t	s_len;
	char	*sub;

	i = 0;
	if (!s)
		return (NULL);
	s_len = ft_strlen(s);
	if (start >= s_len)
		return (ft_strdup(""));
	if (len > s_len - start)
		len = s_len - start;
	sub = (char *)malloc(sizeof(char) * (len + 1));
	if (!sub)
		return (NULL);
	while (i < len && s[start + i])
	{
		sub[i] = s[start + i];
		i++;
	}
	sub[i] = '\0';
	return (sub);
}

/*#include <stdio.h>

int main(void)
{
	char *str;

	str = ft_substr("hello, 42seoul!", 7, 123131231);
	printf("%s", str);
	return (0);
}
*/
## MKO가 발생하지 않는 코드

ft_strjoin

#include "libft.h"

char	*ft_strjoin(char const *s1, char const *s2)
{
	char	*str;
	size_t	s1_len;
	size_t	s2_len;

	s1_len = ft_strlen(s1);
	s2_len = ft_strlen(s2);
	if (!s1 || !s2)
		return (NULL);
	str = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1));
	if (!str)
		return (NULL);
	ft_strlcpy(str, s1, s1_len + 1);
	ft_strlcpy(str + s1_len, s2, s2_len + 1);
	return (str);
}

/*#include <stdio.h>

int main()
{
	const char s1[] = "ppp";
	const char s2[] = "sss";

	printf("%s", ft_strjoin(s1, s2));
	return 0;
}
*/

ft_strtrim

s1의 왼쪽에서 set이 아닌 문자가 나올 때'부터 's1의 오른쪽에서 set이 아닌 문자가 나올 때'까지 자르는 함수이다.

#include "libft.h"

char	*ft_strtrim(char const *s1, char const *set)
{
	size_t	start;
	size_t	end;
	size_t	i;

	if (!s1)
		return (0);
	i = 0;
	start = 0;
	end = ft_strlen(s1) - 1;
	while (s1[i] && ft_strchr(set, s1[i]))
		i++;
	start = i;
	if (start >= ft_strlen(s1))
		return ((char *)ft_calloc(sizeof(char), 1)); //return(ft_strdup(""));
	i = ft_strlen(s1) - 1;
	while (i && s1[i] && ft_strchr(set, s1[i]))
		i--;
	end = i;
	return (ft_substr(s1, start, (end - start + 1)));
}
/*
#include <stdio.h>
int	main(void)
{
	char	s1[] = "abc";
	char	set[] = "";
	char	*str;

	str = ft_strtrim(s1, set);
	printf("%s", str);
}*/

할당 실패시 NULL을 리턴하고, 성공시 자른 문자열을 리턴

ft_split

문장을 구분자를 기준으로 스플릿 해주는 함수

#include "libft.h"

static int	detec_sep(char ori, char c)
{
	if (ori == c)
		return (1);
	return (0);
}

static int	word_count(char const *s, char c)
{
	int	i;
	int	count;

	count = 0;
	i = 0;
	while (s[i])
	{
		while (detec_sep(s[i], c) && s[i])
			i++;
		if (!detec_sep(s[i], c) && s[i])
		{	
			count++;
			while (!detec_sep(s[i], c) && s[i])
				i++;
		}
	}
	return (count);
}

static char	*word_cut(char **words, char const *s, char c)
{
	int		i;
	int		j;
	char	*des;

	j = 0;
	i = 0;
	while (!detec_sep(s[i], c) && s[i] != '\0')
		i++;
	des = (char *)malloc((i + 1) * sizeof(char));
	if (!des)
	{
		free(words);
		return (0);
	}
	while (j < i)
	{
		des[j] = s[j];
		j++;
	}
	des[j] = '\0';
	return (des);
}

char	**ft_split(char const *s, char c)
{
	int		word_num;
	char	**words;
	int		i;
	int		j;

	j = 0;
	i = 0;
	word_num = word_count(s, c);
	words = (char **)malloc(sizeof(char *) * (word_num + 1));
	if (!words)
		return (NULL);
	while (s[i])
	{
		while (s[i] && detec_sep(s[i], c))
			i++;
		if (s[i] != '\0')
			words[j++] = word_cut(words, &s[i], c);
		while (!detec_sep(s[i], c) && s[i])
			i++;
	}
	words[j] = 0;
	return (words);
}

/*#include <stdio.h>

int	main()
{
	char const *s = "aaaaa aaaaa";
	char *c;
	char **word;

	c = " ";
	word = ft_split(s, c[0]);
	for (int i = 0; i < 2; i++)
	{
		printf("%s\n", word[i]);
	}
}*/

1차원 배열 할당 실패시 더블 포인터로 할당해준 배열을 프리해줘야 함.

→ 왜 해줘야 할까..

ft_putchr_fd

fd란 프로세스가 파일을 다룰때 사용하는 개념으로 프로세스에서 특정 파일에 접근할 때 사용하는 추상적인 값이다.

일반적으로 0이 아닌 정수 값을 갖는다.

0 = 표준 입력

1 = 표준 출력

2 = 표준 에러

#include "libft.h"

void	ft_putchar_fd(char c, int fd)
{
	write(fd, &c, 1);
}

ft_putendl_fd

#include "libft.h"

void	ft_putendl_fd(char *s, int fd)
{
	int	i;

	i = 0;
	while (s[i] != '\0')
	{
		write(fd, &s[i], 1);
		i++;
	}
	write(fd, "\n", 1);
}

ft_putstr_fd

#include "libft.h"

void	ft_putstr_fd(char *s, int fd)
{
	int	i;

	i = 0;
	while (s[i] != '\0')
	{
		write(fd, &s[i], 1);
		i++;
	}
}

ft_putnbr_fd

ft_striteri

문자열 's' 의 각 문자를 순회하며 함수 'f'를 적용하고, 해당 문자의 인덱스를 함수 'f'의 첫 번째 인자로 사용합니다. 또한 각 문자의 주소값이 'f' 함수의 두 번째 인자로 사용되며, 경우에 따라 수정될 수 있습니다.

#include "libft.h"

void	ft_striteri(char *s, void (*f)(unsigned int, char*))
{
	unsigned int	i;

	i = 0;
	while (s[i])
	{
		f(i, &s[i]);
		i++;
	}
}

ft_strjoin

#include "libft.h"

char	*ft_strjoin(char const *s1, char const *s2)
{
	char	*str;
	size_t	s1_len;
	size_t	s2_len;

	s1_len = ft_strlen(s1);
	s2_len = ft_strlen(s2);
	if (!s1 || !s2)
		return (NULL);
	str = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1));
	if (!str)
		return (NULL);
	ft_strlcpy(str, s1, s1_len + 1);
	ft_strlcpy(str + s1_len, s2, s2_len + 1);
	return (str);
}

/*#include <stdio.h>

int main()
{
	const char s1[] = "ppp";
	const char s2[] = "sss";

	printf("%s", ft_strjoin(s1, s2));
	return 0;
}
*/

ft_strlcat

strlcat 반환값에 대한 고찰

ft_lstmap

리스트 'lst'의 요소들을 순회하며 각 요소의 content에 함수 'f'를 연속적으로 적용시킵니다. 또한 함수 'f'를 적용시킨 결과물들을 content로 담은 새로운 리스트를 생성합니다. 'del' 함수들은 필요 시 각 요소의 content를 삭제하는 데 사용됩니다.

#include "libft.h"

t_list	*ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *))
{
	t_list	*tmp;
	t_list	*result;
	void	*new;

	result = 0;
	while (lst)
	{
		new = f(lst->content);
		tmp = ft_lstnew(new);
		if (!tmp)
		{
			ft_lstclear(&result, del);
			del(new);
			return (0);
		}
		ft_lstadd_back(&result, tmp);
		lst = lst->next;
	}
	return (result);
}

ft_lstnew

malloc(3) 을 통해 메모리를 할당하고 새로운 요소를 반환합니다. 요소 내의 변수 'content' 는 인자로 받아온 'content' 로 초기화되어야 합니다. 요소 내의 변수 'next'는 NULL로 초기화되어야 합니다.

ft_lstlast

리스트의 맨 마지막에 위치한 요소를 반환합니다.

ft_lstiter

리스트 'lst' 를 순회하며, 리스트에 포함된 모든 요소들의 content에 함수 'f'를 반복적으로 적용시킵니다.

ft_lstclear

0개의 댓글