42Seoul - libft

devicii·2021년 12월 14일
0

42

목록 보기
2/8
post-thumbnail

Makefile

반복적으로 발생하는 컴파일을 쉽게 사용하려고 makefile을 사용한다. 자동화로 시간절약과 실수를 없앨 수 있고 프로그램 관리가 용이하기 때문.

  • libft와 같은 경우에는 한 개의 라이브러리로 만들어야하기 때문에 .c 확장자를 모두 .o 오브젝트 확장아로 만들어서 .a 라이브러리로 묶어준다.

프로토타입

(타겟) : (재료1) (재료2) (재료3)
 	(명령어)

사용법은 make (타겟)을 입력하면 된다. 그냥 make만 한다면 가장 위쪽에 위치한 타겟부터 실행된다.

함수 포인터

선언 방식은 반환값자료형 (*함수포인터이름)();
와 같이 활용할 수 있고, 주의사항으로는 함수 포인터를 선언할 때는 함수 포인터와 저장될 함수의 반환값 자료형, 매개변수 자료형과 개수가 일치해야 한다.

#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!: 함수 포인터로 hello 함수 호출

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

    return 0;
}

출처 : c언어 코딩도장 - 함수 포인터

파일 디스크립터(File Descripter)

파일 디스크립터란 리눅스 혹은 유닉스 환경에서 사용되는 개념으로 파일에 접근할 때 사용하는 추상적인 값이다. 파일 디스크립터는 일반적으로 0이 아닌 정수값을 갖는다.

표준 입력(Standard Input), 표준 출력(Standard Output), 표준 에러(Standard Error)이며 각각 0, 1, 2라는 정수가 할당된다.

-1 : 실패
0 : Standard Input 표준 입력
1 : Standard Ouput 표준 출력 (화면에 출력)
2 : Standard Error 표준 에러 출력
3~ : open함수를 통해 열면 3번부터 fd가 순차적으로 할당된다

static 키워드

우리가 c언어를 사용할 때는 동적으로 작동된다.
그러나 변수나 함수에 static을 붙이게 된다면 변수나 함수는 정적으로 동작하게 된다.
정적 변수는 값이 계속 유지되는 것이 특징이고 그래서 스택 영역이 아닌 메모리 영역에 값이 저장된다. 정적 함수는 같은 소스 코드 안에서만 호출할 수 있다.

atoi

int ft_atoi(const char *str)

*str은 정수로 바꿀 문자열 대상이다

특징

*str에서 넘어오는 문자열을 정수로 반환한다. 정수가 아닌 수를 만나면 종료되며, 화이트 스페이스는 건너뛴다. -를 만난다면 음수로 출력한다. 그러나 -가 연속된다면 0을 반환한다.

풀이


int	ft_atoi(const char *str)
{
	int					i;
	int					sign;
	long long			value;

	sign = 1;
	i = 0;
	value = 0;
	while (str[i] == ' ' || str[i] == '\n' || str[i] == '\t'
		|| str[i] == '\v' || str[i] == '\f' || str[i] == '\r')
		i++;
	if (str[i] == '-')
		sign = -1;
	if (str[i] == '-' || str[i] == '+')
		i++;
	while (str[i] && str[i] >= '0' && str[i] <= '9')
	{
		if (value * sign > 2147483647)
			return (-1);
		else if (value * sign < -2147483648)
			return (0);
		else
			value = value * 10 + (str[i] - '0');
		i++;
	}
	return (value * sign);
}


memmove

void ft_memmove(void ```dest, const void *src, size_t size```)

dest는 붙일 대상(to), src는 복사할 대상(from) size는 크기.

특징

dst < src 라면 똑같이 순차적으로 복사한다. 그러나 dst > src```라면 뒤에서부터 복사한다. return은 dst의 포인터를 반환한다.

풀이


void	*ft_memmove(void *dest, const void *src, size_t size)
{
	unsigned char	*new_dest;
	unsigned char	*new_src;

	if (dest == 0 && src == 0)
	{
		return (0);
	}
	new_dest = (unsigned char *)dest;
	new_src = (unsigned char *)src;
	if (dest < src)
	{
		while (size--)
		{
			*new_dest++ = *new_src++;
		}
	}
	else
	{
		new_dest = (unsigned char *)dest + (size - 1);
		new_src = (unsigned char *)src + (size - 1);
		while (size--)
			*new_dest-- = *new_src--;
	}
	return (dest);
}

strlcat

size_t ft_strlcat(char dest, const char src, size_t size)

dest는 붙일 대상(to), src는 복사할 대상(from) size는 크기.

특징

두 문자열을 붙인다. dest의 맨 뒤에 src를 size만큼 붙인다.
그러나 size가 dest의 사이즈보다 작다면 붙이지 않고, size가 더 크다면 size-1만큼 src를 붙이고 마지막에 '\0'을 넣어주고 리턴 값은 dest + src의 길이를 리턴한다.

풀이



size_t	ft_strlcat(char *dest, const char *src, size_t size)
{
	size_t	src_length;
	size_t	dest_length;
	size_t	i;

	dest_length = ft_strlen(dest);
	src_length = ft_strlen(src);
	i = 0;
	if (size < dest_length)
	{
		return (src_length + size);
	}
	else
	{
		while (src[i] != '\0' && dest_length + 1 + i < size)
		{
			dest[dest_length + i] = src[i];
			i++;
		}
		dest[dest_length + i] = '\0';
		return (dest_length + src_length);
	}
}


strlcpy

size_t _strlcpy(char *dest, const char *src, size_t size)

dest는 붙일 대상(to), src는 복사할 대상(from) size는 크기.

특징

반환은 src의 사이즈를 반환한다. 또한 size가 src의 크기보다 크다면 해당 크기만큼 복사하고 src의 마지막 인덱스에 0을 집어 넣는다.

풀이

size_t	ft_strlcpy(char	*dest, const char *src, size_t size)
{
	size_t	i;

	i = 0;
	if (size == 0)
		return (ft_strlen(src));
	while (size > i + 1 && src[i] != '\0')
	{
		dest[i] = src[i];
		i++;
	}
	dest[i] = '\0';
	return (ft_strlen(src));
}

memcmp

int ft_memcmp(const void *str1, const void *str2, size_t n)

str1는 첫 번째 문자열, str2는 두 번째 문자열 n는 비교할 양.

특징

str1과 str2의 n번째 데이터가 같다면 0, str1이 더 크다면 1, str2가 더 크다면 -1을 반환한다.

풀이


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

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


strnstr

char ft_strnstr(const char ```str, const char *substr, size_t n```)

str1는 찾을 대상 문자열, str2는 찾을 문자열 n는 str에서 찾을 양.

특징

substr이 비었다면 str의 첫 번째 주소값을 리턴한다.
값을 찾았다면 찾은 str의 주소값의 첫 번째 주소값을 리턴한다. 찾지 못하면 0을 리턴한다.

풀이

char	*ft_strnstr(const char *str, const char *substr, size_t n)
{
	size_t			i;
	size_t			j;

	i = 0;
	if (*substr == 0)
	{
		return ((char *)str);
	}
	while (str[i] != 0 && i < n)
	{
		j = 0;
		while (str[i + j] == substr[j] && i + j < n)
		{
			j++;
			if (substr[j] == 0)
			{
				return ((char *)&str[i]);
			}
		}	
		i++;
	}
	return (0);
}

substr

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

*s 함수를 적용할 문자열, start 시작되는 위치(인덱스 기준) len start부터 len만큼 자른다.

특징

성공한다면 잘라낸 문자열이 malloc을 활용해 새로 할당되고,
실패한다면 null을 리턴한다.

풀이


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

	i = start;
	j = 0;
	if (s == 0)
		return (0);
	new_str = malloc(sizeof(char) * (len + 1));
	if (new_str == 0)
		return (0);
	if (start >= ft_strlen(s))
	{
		new_str[0] = 0;
		return (new_str);
	}
	while (j < len && s != 0)
	{
		new_str[j] = s[i];
		i++;
		j++;
	}
	new_str[j] = 0;
	return (new_str);
}

strtrim

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

*s1 함수를 적용할 문자열, *set은 자를 문자

특징

성공한다면 잘라진 문자열, 할당을 실패하면 null

풀이


ft_strtrim("xavocxyzadoyz", "xyz"))가 실행된다면 앞뒤로 xyz가 포함된 문자를 자른다.

그래서 앞, 뒤로 구분해주고 front는 xyz가 포함되지 않는 위치를 기억하고, 
back은 반대로 뒤에서부터 xyz가 포함되지 않는 위치를 기억한다.

char	*ft_strtrim(char const *s1, char const *set)
{
	size_t	front;
	size_t	back;
	char	*new_str;

	new_str = 0;
	if (s1 != 0 && set != 0)
	{
		front = 0;
		back = ft_strlen(s1);
		while (s1[front] && ft_strchr(set, s1[front]))
			front++;
		while (s1[back - 1] && ft_strchr(set, s1[back - 1]))
			back--;
         // back - front + 1를 하면 새로 할당될 문자열 + 맨 뒤 null까지 포함되는 
         //	사이즈만큼 malloc 하게 된다. 
		new_str = malloc((back - front) * sizeof(char));
	}
	if (new_str != 0)
	{
		ft_strlcpy(new_str, &s1[front], (back - front + 1));
		return (new_str);
	}
	else
		return (0);
}

split

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

*s1 함수를 적용할 문자열, c 자를 기준의 캐릭터

특징

성공한다면 스플리팅한 s문자열을 포함한 배열을 반환한다. 또한 배열의 끝은 널이어야 한다.

풀이


static char	**ft_free(char **str)
{
	size_t	i;

	i = 0;
	while (str[i] != 0)
	{
		free(str[i]);
		i++;
	}
	free(str[i]);
	return (0);
}

static char	**do_split(char **new_str, char const *s, char c, size_t count)
{
	size_t	i;
	size_t	j;
	size_t	next;

	i = 0;
	j = 0;
	while (s[i] != 0 && j < count)
	{
		if (s[i] != c)
		{
			next = i + 1;
			while (s[next] != 0 && s[next] != c)
				next++; /2-1. s[next]가 c와 다르다면 계속 next++을 해준다
			new_str[j] = ft_substr(s, i, next - i);
            //2-2 s[next]가 c를 만나면 중단하고 ft_substr을 활용해 new_str에다가 // 할당해준다.
			if (new_str[j] == 0)
            	// 만약 new_str이 비었다면 free를 해줘 메모리를 반환한다.
				return (ft_free(new_str));
			j++;
            
            //2-3그리고 i를 next로 할당하므로 출발점을 바꿔준다. 계속 반복하면서 c를 만날 // 때마다 로직이 반복되고 배열의 끝을 만나면 종료된다.
			i = next;
		}
		else
			i++;
	}
    //2-4 배열의 끝에 0을 넣어준다.
	new_str[j] = 0;
	return (new_str);
}

char	**ft_split(char const *s, char c)
{
	char	**new_str;
	size_t	word_count;
	size_t	i;

	if (s == 0)
		return (NULL);
	i = 0;
	word_count = 0;
	while (s[i] != 0)
	{
		if (s[i] != c)
		{
			word_count++; //1.word_count 변수에 적용해야할 단어의 수를 담는다.
			while ((s[i] != c) && s[i] != 0)
				i++;
		}
		else
			i++;
	}
    2. new_str을 malloc을 통해서 할당해준다 +1을 하는 이유는 null을 채우기 위해서
	new_str = malloc(sizeof(char *) * word_count + 1);
	if (new_str == 0)
		return (0);
     3. 유효성 확인 후 do_split을 실행한다
	do_split(new_str, s, c, word_count);
	return (new_str);
}

strmapi

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

*s 문자열 원형, (*f)(unsigned int, char) 문자열 원형을 적용할 함수 포인터

특징

f함수에 따라 s의 length만큼 아웃풋이 나온다.

풀이


char	*ft_strmapi(char const *s, char (*f)(unsigned int, char))
{
	size_t	length;
	size_t	i;
	char	*new_str;

	i = 0;
    if (!s || !f)
	{
		return (0);
	}
	length = ft_strlen(s);
	new_str = malloc(length * sizeof(char) + 1);
	if (new_str == 0)
	{
		return (0);
	}
	while (i < length)
	{
		new_str[i] = f(i, s[i]); // 인자로 전달받은 f함수의 로직에 따라 인풋이 								  //모두 다르다.
		i++;
	}
	new_str[i] = 0;
	return (new_str);
}

itoa

char *ft_itoa(int n)

n 입력받는 정수

특징

입력받은 정수를 모두 문자열로 바꾸는 함수이다.

풀이



#include "libft.h"

size_t	ft_int_length(int n)
{
	size_t	length;

	if (n == 0)
	{
		return (1);
	}
	length = 0;
	if (n < 0)
	{
		length++;
	}
	while (n != 0)
	{
		n /= 10;
		length++;
	}
	return (length);
}

char	*ft_itoa(int n)
{
	before -> int		value; 
    //여기를 int로 했었는데 오버플로우가 나면서 -2147483647를 넣는 상황을 조심해야한다. 
    //그래서 long value로 바꾸니 해결됐다.
	after -> long		value;
    size_t	length;
	char	*new_str;

	length = ft_int_length(n);
	value = n;
	new_str = malloc(length * sizeof(char) + 1);
	if (new_str == 0)
		return (0);
	if (value < 0)
	{
		new_str[0] = '-';
		value *= -1;
	}
	if (value == 0)
		new_str[0] = '0';
	new_str[length] = 0;
	length -= 1;
	while (value != 0)
	{
		new_str[length] = '0' + value % 10;
		length--;
		value /= 10;
	}
	return (new_str);
}


profile
Life is a long journey. But code Should be short :)

0개의 댓글