[libft] Part 1

James An·2020년 12월 31일
0

42SEOUL

목록 보기
1/11
post-thumbnail

Makefile

Makefile

  • Makefile을 이용하면 일일이 gcc 명령어를 사용하지 않고 컴파일을 진행할 수 있고, Incremental build 기능은 전과 후를 비교해 이전과 차이가 없는 대상은 컴파일하지 않는다. 즉, 차이가 생긴 대상만 컴파일을 진행시킬 수 있다.
  • Makefile 원리
  • -l 옵션 : 전처리 과정에서 헤더 파일을 탐색하는 기본 디렉토리를 추가할 때 사용하는 옵션

AR

  • ar(archive)은 묶음파일을 만들고 조작하고 추출한다
  • option
    • r: 오브젝트 추가
      새로운 오브젝트 파일이면 추가, 기존 파일이면 치환함.
    • c: 아카이브 생성
    • s: 인덱스 생성
      인덱스를 생성하지 않으면 링크 속도가 느려지고, 시스템 환경에 따라서는 에러가 발생.

libft

  • Libft 프로젝트는 C 표준 라이브러리에 있는 함수를 직접 구현해보는 프로젝트이다.
  • 앞으로 프로젝트에 필요한 함수들은 libft에 추가해 라이브러리로 사용하자.

1. memset

Prototype

void *ft_memset(void *s, int c, size_t n);

#include "libft.h"

void	*ft_memset(void *s, int c, size_t n)
{
	size_t idx;

	idx = 0;
	while (idx < n)
	{
		*((unsigned char *)s + idx) = c;
		idx++;
	}
	return (s);
}

Description

메모리 주소의 시작점부터 n바이트만큼 c값으로 채우는 함수

Unsigned char를 사용하는 이유

  • unsigned char 는 모든 bit 를 투명하게 볼 수 있는 특성을 제공합니다.
    즉, 다른 type 은 내부 비트의 일부를 값을 표현하기 위한 용도가 아닌
    다른 용도로 사용할 수 있으나 unsigned char 는 이것이 허락되지
    않습니다.
    따라서, 임의의 메모리에 바이트 단위로 접근해 값을 다룰 때에는 반드시 unsigned char 를 사용해야 full portability 를 얻을 수 있는 것입니다.
    또한, 그와 같은 이유로 signed char 가 표현할 수 있는 값의 개수보다 unsigned char 가 표현할 수 있는 값의 개수가 많다는 사실에도 유의할 필요가 있습니다. signed char <-> unsigned char 사이의 값 변환이 1:1 로 이루어질 수 "없는" 경우도 있음을 의미합니다.

참고 사이트

2. bzero

Prototype

void ft_bzero(void *s, size_t n);

#include "libft.h"

void	ft_bzero(void *s, size_t n)
{
	size_t idx;

	idx = 0;
	while (idx < n)
	{
		*((unsigned char *)s + idx) = 0;
		idx++;
	}
}

Description

  • 메모리 주소의 시작점부터 n바이트만큼 0으로 채우는 함수

3. memcpy

Prototype

void *ft_memcpy(void *dest, const void *src, size_t n);

#include "libft.h"

void	*ft_memcpy(void *dest, const void *src, size_t n)
{
	unsigned char		*d;
	const unsigned char	*s;

	d = dest;
	s = src;
	if (dest == '\0' && src == '\0')
		return (0);
	while (n--)
		*d++ = *s++;
	return (dest);
}

Description

  • src가 가르키는 메모리에 접근해서 n바이트 만큼 dest가 가르키는 메모리에 복사하는 함수
  • srcnull 문자 종료를 고려하지 않는다.
  • 언제나 n바이트 만큼 복사한다.
  • 두 메모리가 겹친다면 있다면 memmove를 사용해야한다.
  • memcpystrcpy의 차이는 byte string, string이므로 null값을 고려해야한다.

4. memccpy

Prototype

void *ft_memccpy(void *dest, const void *src, int c, size_t n);

#include "libft.h"

void	*ft_memccpy(void *dest, const void *src, int c, size_t n)
{
	unsigned char		*d;
	const unsigned char	*s;
	unsigned char		find;

	d = dest;
	s = src;
	find = c;
	while (n--)
	{
		*d = *s;
		if (*s == find)
			return (d + 1);
		d++;
		s++;
	}
	return (NULL);
}

Description

  • src 데이터에서 n바이트만큼 dest에 복사한다.
  • src 데이터에서 문자 c가 있다면 복사를 중단하고 dest의 다음 번지를 return한다. c를 찾지 못하고 n바이트만큼 복사를 마치면 NULLreturn한다.

5. memmove

Prototype

void *ft_memmove(void *dest, const void *src, size_t n);

#include "libft.h"

void			*ft_memmove(void *dest, const void *src, size_t n)
{
	unsigned char	*new_d;
	unsigned char	*new_s;

	if (dest == src || n == 0)
		return (dest);
	if (dest < src)
	{
		new_d = (unsigned char *)dest;
		new_s = (unsigned char *)src;
		while (n--)
			*new_d++ = *new_s++;
	}
	else
	{
		new_d = (unsigned char *)dest + (n - 1);
		new_s = (unsigned char *)src + (n - 1);
		while (n--)
			*new_d-- = *new_s--;
	}
	return (dest);
}

Description

  • 특정 메모리영역을 다른 메모리 영역에 n바이트만큼 복사할 때 사용한다.
  • srcdest 의 메모리 영역과 겹치지 않는 메모리 영역부터 먼저 복사하기 때문에. destsrcoverlap 되는 경우에도 데이터를 안전하게 복사 할 수 있다는 점이 memcpy와 다르다.
  • dest < src
    12345
    ---abcde
  • dest > src
    ---12345
    abcde

참고사이트

6. memchr

Prototype

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

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

	find = c;
	ptr = (unsigned char *)s;
	while (n--)
	{
		if (*ptr == find)
			return ((void *)ptr);
		ptr++;
	}
	return (NULL);
}

Description

  • s가 가르키는 메모리 블록에서 n바이트까지 문자 c가 있는지 탐색한다. 문자 c를 처음으로 찾은 주소를 return하고, 없다면 NULLreturn 한다.

Problem

  • returning 'const unsigned char ' from a function with result type 'void ' discards qualifiers
  • c를 찾은 주소를 return할 때 return (ptr); 로 작성해 발생한 오류이다. void로 형변환을 해주고 반환하기 위해 return (void *)prt로 바꿔 해결했다.

7. memcmp

Prototype

int ft_memcmp(const void *s1, const void *s2, size_t n);

#include "libft.h"

int	ft_memcmp(const	void *s1, const	void *s2, size_t n)
{
	unsigned char	*u1;
	unsigned char	*u2;
	int				idx;

	u1 = (unsigned char *)s1;
	u2 = (unsigned char *)s2;
	idx = 0;
	while (n--)
	{
		if (u1[idx] != u2[idx])
			return (u1[idx] - u2[idx]);
		idx++;
	}
	return (0);
}

Description

  • s1, s2가 가르키는 메모리의 시작점부터 n바이트까지 값을 비교하는 함수이다.
  • n바이트까지 동일하다면 0return하고, 일치하지 않으면 해당 바이트에서의 unsigned char로 해석했을 때 s1이 더 크다면 0보다 큰 값을 반환하고, 작다면 0보다 작은 값을 반환한다.
  • strncmpmemcmp가 다른 점은 strncmp의 경우 s1s2 둘 중 하나가 NULL인 경우 n바이트까지 비교하지 않고, 그 때의 값을 비교하지만 memcmpNULL인 경우를 고려하지 않고 n바이트까지 비교한다.

8. strlen

Prototype

size_t ft_strlen(const char *s);

#include "libft.h"

size_t	ft_strlen(const char *s)
{
	size_t idx;

	idx = 0;
	while (s[idx])
		idx++;
	return (idx);
}

Description

  • 매개변수로 주어진 문자열 s의 길이를 구하는 함수

9. strlcpy

Prototype

size_t ft_strlcpy(char *dst, char *src, size_t size);

#include "libft.h"

size_t	ft_strlcpy(char *dst, char *src, size_t size)
{
	size_t idx;

	idx = 0;
	if (!dst || !src)
		return (0);
	if (!size)
		return (ft_strlen(src));
	while (src[idx] && idx < size - 1)
	{
		dst[idx] = src[idx];
		idx++;
	}
	dst[idx] = '\0';
	return (ft_strlen(src));
}

Description

  • size - 1 만큼 src의 데이터를 dest로 복사한 후, src의 길이를 반환하는 함수
  • 복사가 이루어진 dest 문자열은 반드시 NULL로 종료한다.

10. strlcat

Prototype

size_t ft_strlcat(char *dst, const char *src, size_t size);

#include "libft.h"

size_t	ft_strlcat(char *dst, const char *src, size_t size)
{
	size_t	idx;
	size_t	dst_len;
	size_t	src_len;

	dst_len = ft_strlen(dst);
	src_len = ft_strlen(src);	
	if (size < dst_len + 1)
		return (src_len + size);
	idx = 0;
	while (src[idx] && idx < size - dst_len - 1)
	{
		dst[dst_len + idx] = src[idx];
		idx++;
	}
	dst[dst_len + idx] = '\0';
	return (dst_len + src_len);
}

Description

  • src의 메모리의 시작점부터 최대 size - dst_len - 1개까지 dst의 뒷 부분에 복사한다.
  • 복사가 이루어진 dest 문자열은 반드시 NULL로 종료시킨다.
  • sizedst_len보다 작거나 같다면 src_len + size를 반환한다.
  • sizedst_len보다 크다면 복사가 이루어지고 dst_len + src_len을 반환한다.

11. strchr

Prototype

char *ft_strchr(const char *s, int c);

#include "libft.h"

char		*ft_strchr(const char *s, int c)
{
	char		find;
	int		idx;

	find = (unsigned char)c;
	idx = 0;
	while (s[idx])
	{
		if (s[idx] == find)
			return ((char *)s + idx);
		idx++;
	}
	if (s[idx] == find)
		return ((char *)s + idx);
	return (0);
}

Description

  • 문자열에서 특정 문자를 처음 찾게되는 위치를 반환하는 함수
  • 찾는 문자가 없다면 NULL 포인터를 반환한다.
  • 문자열의 마지막 NULL 문자도 찾는 문자 c가 될 수 있기때문에 문자열의 마지막 위치를 찾을 때 사용하기도 한다.

12. strrchr

Prototype

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

#include "libft.h"

char		*ft_strrchr(const char *s, int c)
{
	char	find;
	int		idx;
	int		s_len;

	s_len = ft_strlen(s);
	find = c;
	idx = s_len - 1;
	if (s[idx + 1] == find)
		return ((char *)s + idx + 1);
	while (s_len--)
	{
		if (s[idx] == find)
			return ((char *)s + idx);
		idx--;
	}
	return (0);
}

Description

  • 문자열에서 특정 문자를 마지막으로 찾게되는 위치를 반환하는 함수
  • 찾는 문자가 없다면 NULL 포인터를 반환한다.
  • 문자열의 마지막 NULL 문자도 찾는 문자 c가 될 수 있기때문에 문자열의 마지막 위치를 찾을 때 사용하기도 한다.

13. strnstr

Prototype

char *ft_strnstr(const char *big, const char *little, size_t len);

#include "libft.h"

char	*ft_strnstr(const char *big, const char *little, size_t len)
{
	size_t l_len;

	l_len = ft_strlen(little);
	if (*big == '\0')
		return (NULL);
	if (*little == '\0')
		return ((char *)big);
	while (len-- >= l_len && *big != '\0')
	{
		if (*big == *little && ft_strncmp(big, little, l_len) == 0)
			return ((char *)big);
		big++;
	}
	return (NULL);
}

Description

  • big문자열의 len길이 중에서 little과 일치하는 영역을 찾고, 그 시작 위치를 반환하는 함수
  • big이 비어있거나 동일한 영역이 없다면 NULL을 반환한다.
  • little이 비어있다면 big의 시작 위치를 반환한다.
  • lenlittle의 길이보다 작다면 비교하는 의미가 없으므로 NULL을 반환한다.

Problem

  • Seg fault가 뜸. 즉, 잘못된 메모리 참조를 했다는 의미.
  • 원인은 big과 little 둘 다 NULL인 경우, little이 NULL이기때문에 big의 포인터 주소를 반환해야하지만 ft_strnstr은 NULL값을 반환하고 있었다.

    const char big = "";
    const char
    little = "";
    ft_strnstr: 0x0 (NULL)
    strnstr: 0x10bdbff8c (big의 포인터 주소)

/* 9번 라인에 위치한 코드로 인해 NULL을 반환해버렸던 것... */
if (*big == '\0')
		return (NULL);
/* 문제가된 조건을 수정하고 while, if 문의 코드를 좀 더 간결하게 다듬었다. */
char	*ft_strnstr(const char *big, const char *little, size_t len)
{
	size_t l_len;

	if (*little == '\0')
		return ((char *)big);
	l_len = ft_strlen(little);
	while (*big && l_len <= len--)
	{
		if (!ft_strncmp(big, little, l_len))
			return ((char *)big);
		big++;
	}
	return (NULL);
}

14. atoi

Prototype

int ft_atoi(const char *nptr);

#include "libft.h"

int		ft_isspace(char c)
{
	if (c == ' ' || c == '\t' || c == '\n' || c == '\v' || \
			c == '\r' || c == '\f')
		return (1);
	else
		return (0);
}

int		ft_atoi(const char *nptr)
{
	long	nbr;
	long	minus;
	int		idx;

	nbr = 0;
	minus = 1;
	idx = 0;
	while (ft_isspace(nptr[idx]) && nptr[idx] != '\0')
		idx++;
	if (nptr[idx] == '-')
		minus = -1;
	if (nptr[idx] == '+' || nptr[idx] == '-')
		idx++;
	while (nptr[idx] != '\0' && ('0' <= nptr[idx] && nptr[idx] <= '9'))
	{
		nbr = (nbr * 10) + (nptr[idx] - '0');
		if (nbr > 2147483647 && minus == 1)
			return (-1);
		if (nbr > 2147483648 && minus == -1)
			return (0);
		idx++;
	}
	return (minus * nbr);
}

Description

  • 매개변수로 주어진 문자열정수로 변환하는 함수
  • ft_isspace(char c) 함수를 통해 문자열의 공백을 탐색한다.
  • +-부호에 대한 처리를 해줘야한다.
  • 0과 9 사이의 문자가 아닌 경우NULL 값을 만나기 전까지 탐색한다.
  • int음수 범위인 -2147483648양수로 표현이 불가능하므로 따로 예외 처리함.

15. isalpha

Prototype

int ft_isalpha(int c);

#include "libft.h"

int	ft_isalpha(int c)
{
	if ((65 <= c && c <= 90) || (97 <= c && c <= 122))
		return (1);
	return (0);
}

Description

  • 문자 calphabat 인지 검사하여 10으로 반환하는 함수

    isdigit, isalnum, isascii, isprint도 동일한 원리로 구현

16. toupper

Prototype

int ft_toupper(int c);

#include "libft.h"

int	ft_toupper(int c)
{
	if (97 <= c && c <= 122)
		return (c - 32);
	return (c);
}

Description

  • 문자 c가 소문자에 해당되면 대문자로 변환하는 함수

    tolower는 대문자에 해당되면 소문자로 변환하는 함수

17. calloc

Prototype

void *ft_calloc(size_t nmemb, size_t size);

#include "libft.h"

void		*ft_calloc(size_t nmemb, size_t size)
{
	void	*p;

	p = malloc(nmemb * size);
	if (!p)
		return (p);
	ft_bzero(p, nmemb * size);
	return (p);
}

Description

  • size 크기의 변수를 nmemb개 만큼 저장할 수 있는 메모리 공간을 할당하고 할당된 공간을 0으로 초기화한다.
  • nmemb: number of members. 즉, count라고 생각하면된다.

18. strdup

Prototype

char *ft_strdup(const char *s)

char		*ft_strdup(const char *s)
{
	int		s_len;
	int		idx;
	char	*p;

	s_len = ft_strlen(s);
	p = (char *)malloc(sizeof(char) * (s_len + 1));
	if (!p)
		return (NULL);
	idx = 0;
	while (s[idx])
	{
		p[idx] = s[idx];
		idx++;
	}
	p[idx] = '\0';
	return (p);
}

Description

  • 문자열 s를 복사한 후에 복사된 문자열을 가르키는 포인터를 반환하는 함수
  • 내부적으로 동적할당이 이루어진다.
  • strdupmalloc을 사용해 문자열을 복사하기때문에 사용하지 않으면 free로 메모리를 해제해줘야한다.
profile
born 2 code :)

0개의 댓글