libft : [part_1]

friend463·2021년 7월 29일
0

libft : [part_1]

  • man을 한번씩 확인하여 설명을 읽고 함수의 원본과 동일한 프로토타입 및 기능을 수행하는 코드 작성 필요
    (sibject에도 그렇게 설명되어 있고, 그냥 찾아서 하다가 매개변수의 자료형, 리턴값 등 재수정하게 된다.)
  • 일일이 찾는 것보다 한 번에 정리된 블로그들을 참고하는 것이 시간 절약이 된다.





1.1 체크

🔹 ft_isalpha

//#include <ctype.h>
int	ft_isalnum(int c)
  • 알파벳인지 검사하는 함수

✔️ Return

  • 알파벳이면 0이 아닌 정수 반환
  • 아니면 0을 반환


🔹 ft_isdigit

//#include <ctype.h>
int	ft_isdigit(int c)
  • 숫자인지 검사하는 함수

✔️ Return

  • 숫자이면 0이 아닌 정수 반환
  • 아니면 0을 반환



🔹 ft_isalnum

//#include <ctype.h>
int	ft_isalnum(int c)
  • 알파벳 또는 숫자인지 검사하는 함수

✔️ Return

  • 알파벳 또는 숫자이면 0이 아닌 정수 반환
  • 아니면 0을 반환



🔹 ft_isascii

 //#include <ctype.h>
 int	ft_isascii(int c)
  • ASCII코드 문자(0~127)인지 검사하는 함수

✔️ Return

  • 아스키코드 값이면 1을 반환
  • 아니면 0을 반환



🔹 ft_isprint

 //#include <ctype.h>
int	ft_isprint(int c)
  • 출력할 수 있는 문자(아스키코드 32~126)인지 검사하는 함수

✔️ Return

  • 출력 가능한 문자이면 0이 아닌 정수 반환
  • 아니면 0을 반환
  • 아스키코드 공백 문자(9~13)는 출력 가능한 문자가 아님 / 예시 확인





1.2 변환

🔹 ft_toupper

//#include <ctype.h>
int	ft_toupper(int c)
  • 소문자를 대문자로 변환하는 함수 (아스키코드 a=97, A=65)

✔️ Return

  • 소문자이면 대문자로 변환하여 반환
  • 소문자가 아니면 그대로 반환



🔹 ft_tolower

//#include <ctype.h>
int	ft_tolower(int c)
  • 대문자를 소문자로 변환하는 함수 (아스키코드 a=97, A=65)

✔️ Return

  • 대문자이면 소문자로 변환하여 반환
  • 대문자가 아니면 그대로 반환


🔹 ft_atoi

//#include <stdlib.h>
int	ft_atoi(const char *str)
  • 정수형 문자열(char 타입)을 정수(int 타입)로 변환하는 함수
    (ex - “ \t - 123abc”)
  • atof(float) / atoi(int) / atol(long) / atoll(long long) 존재

✔️ Description

  • <반복문> 처음 공백 문자(아스키코드 9 ~ 13, 32) 처리 / 아스키코드표
  • <조건문> 부호 처리(부호는 하나만 들어올 수 있음)
  • 부호가 2개 이상인 경우 0으로 처리
  • <반복문> 부호 검사 후, 연속된 문자형 정수만 읽어들여 정수로 변환
  • 숫자를 제외한 문자열이 나오는경우 그 전까지의 숫자들만 인식

✔️ Return

  • 성공 시 변환된 정수 값 반환
  • 실패 시 0
  • atoi()함수의 man 설명에 의하면 오류 처리를 따로 하지 않는다고 함

✔️ !! Notice

  • atoi()함수의 man 설명에 의하면 오류 처리를 따로 하지 않는다고 함
  • 하지만 libft-unit-test 테스터기 경우 long long의 MAX, MIN 값의 오버/언더플로우를 체크한다.
  • long long 최대값, 최소값 오버/언더플로우 예외처리
    • 변환한 정수가 LLONG_MAX보다 크면 -1(오버플로우), LLONG_MIN 보다 작으면 0(언더플로우) 반환(그냥 INT_MAX로 하면된다.)
    • atoi() 함수는 libc에 의해 stdtol()를 내부에서 돌려 long 타입의 결과값을 리턴한다.
    • 이 과정에서 long 오버플로우 시 (-1), 언더플로우 시 (0)을 리턴
    • long max(9223372036854775807), long min(-9223372036854775808)
  • 결론은 기계평가에서 long의 오버플로우, 언더플로우까지 검사하지 않는다고 하는데 unit-test의 테스터기에서는 확인을 한다.
  • 잘 정리해주신 분의 글을 참조
    https://velog.io/@mjung/libft.hftatoi-underflow-overflow%EC%B2%98%EB%A6%AC-%EA%B4%80%EB%A0%A8-%EC%82%BD%EC%A7%88

📢 Int, Long 차이점

  • 크기 : 4 Byte
  • Long : 어느 플랫폼에서든 4 Byte (32비트, 64비트 등의 어느 플랫폼에서든)
  • Int : CPU의 레지스터와 동일한 크기를 가지는 타입으로 레지스터가 32비트이면 32비트(4 Byte), 64비트면 64비트(8 Byte)가 된다.





1.3 메모리 할당

🔹 ft_calloc

//#include <stdlib.h>
void	*ft_calloc(size_t count, size_t size)
  • 크기와 개수에 따라 메모리를 할당하고 0으로 초기화하는 함수

✔️ Description

  • count : 할당할 메모리의 개수(길이)
  • size : 메모리 하나의 크기

✔️ Return

  • 메모리 할당 성공 시 초기화 후 할당된 메모리 주소 반환
  • 메모리 할당 실패 시 NULL 반환

✔️ !! Notice

  • calloc() = malloc() + memset()

  • overflow 여부 확인 가능

    • malloc은 size_t의 MAX 값을 넘어 메모리 할당할 경우 잘못된 메모리를 할당 받지만, calloc은 크기와 자료형 사이즈를 받기 때문에 내부에서 NULL로 처리하여 반환할 수 있다.
  • ?calloc()함수 내에서 char *를 만들어 메모리 할당 후 0으로 세팅하여 void *로 반환한다면 다른 타입으로 쓸 수 있는가?

    • 포인터의 변환 및 메모리 공간 이해 필요
    • char *로 메모리를 초기화 하면 char(1byte) 단위로 해석한다.
    • int *로 메모리를 초기화 하면 int(4byte) 단위로 해석한다.
  • void 포인터



🔹 ft_strdup

//#include <string.h>
char	*ft_strdup(const char *s1)
  • 주어진 문자열을 새로운 메모리에 메모리를 할당하여 복사 후 반환하는 함수

✔️ Return

  • 복사 성공 시 복사한 문자열 반환
  • 메모리 할당 실패 시 NULL 반환

✔️ !! Notice

  • 메모리를 할당하여 메모리 사용이 끝나면 반드시 free를 사용하여 메모리를 해제해야 한다.






1.4 메모리

🔹 ft_bzero

//#include <strings.h>
void	ft_bzero(void *s, size_t n)
  • 시작점(s)에서 주어진 바이트(n) 만큼 0으로 초기화하는 함수

✔️ Return

  • 없음



🔹 ft_memset

//#include <string.h>
void	*ft_memset(void *b, int c, size_t len);
  • 시작점(b)에서 주어진 바이트(len) 만큼 (c)로 초기화 하는 함수

✔️ Description

  • b : 메모리 시작 주소
  • c : 메모르에 초기화시키는 값
  • len : 초기화할 바이트 수
  • 문자 c의 타입이 int이지만 내부에서 unsigned char로 변환해서 처리

✔️ Return

  • 성공 시 첫번째 인자 값이 있는 b 반환

✔️ !! Notice

  • memset()이 문자c 를 채울 때는 char단위(1Byte)로 채운다.

  • 바이트 단위로 초기화 하기 때문에 int형 배열을 초기화 할 때 주의해야 한다. (ing형은 4바이트 이므로 4번처리가 된다.

    • EX : 1로 초기화시
      00000001 00000001 00000001 00000001
  • unsigned char를 쓰는 이유



🔹 ft_memcpy

//#include <string.h>
void    *ft_memcpy*ft_memcpy(void *dst, const void *src, size_t n)
  • dst가 가리키는 메모리부터 주어진 바이트(n) 만큼 src을 복사하는 함수

✔️ Description

  • dst : 복사될 문자열의 시작 주소
  • src : 복사할 데이터들의 주소
  • n : 복사할 데이터의 바이트 수
  • 메모리 함수는 문자열의 끝을 알리는 \0에서 멈추지 않고, 주어진 바이트만큼을 복사함
  • 그래서 복사할 때는 \0'의 길이도 계산 해야 한다. (문자열 길이 + 1)

✔️ Return

  • 복사한 포인터 dst 반환

✔️ !! Notice

  • 사용시 dstsrc의 메모리 영역이 오버랩이 발생 할 수 있을때memmove()함수를 사용



🔹 ft_memccpy (과제 제외)

//#include <string.h>
void	*ft_memccpy(void *restrict dst, const void *restrict src, int c, size_t n)
  • dst가 가리키는 메모리부터 주어진 바이트(n) 만큼 src을 복사하는데 문자 c을 찾으면 c 다음 주소 값을 반환, 찾지 못하면 NULL값 반환하는 함수

✔️ Description

  • dst : 복사될 문자열의 시작 주소
  • src : 복사할 데이터들의 주소
  • c : 중단할 데이터
  • n : 복사할 데이터의 바이트 수

✔️ Return

  • n 바이트 이전까지 c을 찾으면 그다음 주소값을 반환
  • 찾지 못하면 NULL 반환

✔️ !! Notice

  • memcpy()와 똑같이 dstsrc의 메모리 영역이 오버랩이 발생 할 수 있음


🔹 ft_memmove

//#include <string.h>
void	*ft_memmove(void *dst, const void *src, size_t len);
  • memcpy()처럼 dst가 가리키는 메모리부터 주어진 바이트(len) 만큼 src을 복사하는 함수
  • 단, 오버랩 예외 처리함

✔️ Description

  • dst : 복사가 될 곳의 시작 주소
  • src : 복사할 데이터들의 주소
  • len : 복사할 데이터의 바이트 수
  • memmove()memcpy()와 달리 메모리가 겹치는 상태에서의 불상사를 피할 수 있다.
  • memcpy()와의 차이점은 복사를 할 때 메모리 오버랩 예외 처리를 하냐 안 하냐의 차이, mommove()는 오버랩 예외 처리함
    • 주소값이 dst < src 인 경우
      • 앞에서부터 한 바이트씩 복사
    • 주소값이 dst > src 인 경우
      • 뒤에서부터 한 바이트씩 복사
  • memmove 사용법 및 구현 참고

✔️ Return

  • 복사한 포인터 dst 반환


🔹 ft_memchr

//#include <string.h>
void	*ft_memchr(const void *s, int c, size_t n)
  • : 주어진 바이트(n)까지 c 문자를 찾으면 해당 주소를 반환, 아닐 시 NULL반환하는 함수

✔️ Description

  • s : 검색을 할 문자열 주소
  • c : 찾을 문자
  • n : 검색할 데이터의 바이트 수

✔️ Return

  • 일치하는 값이 있으면 그 주소값을 반환

  • 찾지 못했다면 NULL 반환



🔹 ft_memcmp

//#include <string.h>
int	ft_memcmp(const void *s1, const void *s2, size_t n)
  • : 주어진 바이트까지 두 메모리 블록의 내용이 같은지 비교하는 함수

✔️ Description

  • s1 : 비교할 문자열_1
  • s2 : 비교할 문자열_2
  • n : 검색할 데이터의 바이트 수

✔️ Return

  • 두 문자열이 같으면 0을 반환
  • 다르면 (s1 - s2)값을 반환

✔️ !! Notice

  • 한 바이트씩 비교하기 때문에 unsigned char 로 형변환
  • strcmp와 비교하면 strcmp는 널값까지 비교를 하지만, memcmp는 중간에 널값이 있어도 주어진 바이트까지 검사한다.





1.5 문자열

🔹 ft_strlen

//#include <string.h>
int	ft_strlen(const char *s)
  • 문자열 길이를 구하여 반환

✔️ Return

  • 문자열 s의 길이를 반환



🔹 ft_strchr

//#include <string.h>
char	*ft_strchr(const char *s, int c)
  • 주어진 문자를 찾아 주소값 반환, 없으면 NULL 반환

✔️ Description

const char *s : 주어진 문자를 찾을 문자열 주소
int c : 검색할 문자 ('\0'도 포함)

✔️ Return

  • 주어진 문자를 찾으면 그 주소값 반환
  • 없으면 NULL 반환

✔️ !! Notice

  • return (NULL) 과 return ("")은 다르다
    • NULL은 그냥 NULL을 말하지만 ("")은 '\0'값이 들어있는 주소를 가리키는 char *를 말한다.
    • c값이 '\0'값이면 문자열 s'\0'값이 들어있는 주소값을 반환하는 조건도 처리해야 한다.
    • return (NULL) vs return ("")


🔹 ft_strrchr

//#include <string.h>
char	*ft_strrchr(const char *s, int c)
  • 주어진 문자를 찾는데 마지막으로 찾은 문자의 주소값 반환, 없으면 NULL 반환

✔️ Description

const char *s : 주어진 문자를 찾을 문자열 주소
int c : 검색할 문자 ('\0'도 포함)

✔️ Return

  • 가장 마지막에 찾은 문자의 주소값 반환
  • 없으면 NULL 반환

✔️ !! Notice

  • return (NULL) 과 return ("")은 다르다

    • NULL은 그냥 NULL을 말하지만 ("")은 '\0'값이 들어있는 주소를 가리키는 char *를 말한다.
    • c값이 '\0'값이면 문자열 s'\0'값이 들어있는 주소값을 반환하는 조건도 처리해야 한다.
    • return (NULL) vs return ("")
  • s == 0;s[0] = '\0';의 차이.

    • char * s = "" <- 이건 빈문자열

    • char *s = NULL <- 이건 그냥 s포인터가 가르키는게 없는 것(NULL 인거)

      • s를 리턴 받았을 때,
        전자는 s[0] == '\0' 이라서 문자열의 끝이 바로 검색되고
        후자는 s[0] 값 자체를 보려고하면 세그먼트 폴트가 뜬다.



🔹 ft_strnstr

//#include <string.h>
char	*ft_strnstr(const char *haystack, const char *needle, size_t len)
  • 문자열1haystack에서 주어진 길이 len만큼 문자열2needle이 있는지 확인, 있으면 그 주소값, 없으면 0반환

✔️ Description

const char *haystack : 주어진 문자열s2를 찾을 문자열 주소
const char *needle : 찾을 문자열의 시작 주소
size_t len : 검색할 데이터의 바이트 수

✔️ Return

  • needle가 없으면 haystack 주소 반환
  • needle를 찾으면 haystack에서 찾은 주소 반환
  • 찾지 못하면 NULL 반환

✔️ !! Notice

  • const char *으로 작업 후 char *형으로 형변환 후 반환해야 한다.


🔹 ft_strlcpy

//#include <string.h>
size_t	ft_strlcpy(char *dst, const char *src, size_t dstsize)
  • strdst에 <size - 1(널값)> 만큼 복사 후 str 총 길이를 반환

✔️ Description

char *dst : 복사될 문자열 시작 주소
const char *src : 복사할 문자열의 시작 주소
size_t dstsize : 복사할 데이터의 바이트 수

✔️ Return

  • src 길이를 반환
  • dstsrc 가 NULL 인 경우, 0 을 반환함.

✔️ !! Notice

  • strlcat, strlcpy 함수는 보안 목적을 위해 만들어진 함수임. 실수하지 않도록 안전하고 오류발생률을 낮춰 철저히 디자인 되었음.
  • 기존의 strncpy 에서는 src 의 길이가 dst 의 길이와 같거나 더 길 경우, 끝에 NULL 이 들어가지 않음. 하지만 strlcpy 에서는 마지막에 반드시 NULL 종료가 되도록 보증함.



🔹 ft_strlcat

//#include <string.h>
size_t	ft_strlcat(char *dst, const char *src, size_t dstsize)
  • strdest에 <size -1(널값)> 만큼 붙인다(복사한다).

✔️ Description

  • dst : 복사될 문자열 시작 주소
  • src : 복사할 문자열 시작 주소
  • dstsize : 복사할 데이터 바이트 수

✔️ Return

  • dst > dstsize : src길이 + dstsize 반환
    (복사할 수 있는 경우)
  • dst < dstsize : src길이 + dst 반환
    (복사할 수 없는 경우)

✔️ !! Notice

  • strlcat()함수는 dst, src가 NULL인 경우 에러가 발생한다. 실제 lib 함수도 동일하게 에러가 발생한다.


🔹 ft_strncmp

//#include <string.h>
int	ft_strncmp(const char *s1, const char *s2, size_t n)
  • : 두 문자열을 주어진 길이만큼 같은지 비교

✔️ Description

const char s1 : 비교할 문자열1 시작 주소
const char
s2 : 비교할 문자열2 시작 주소
size_t n : 비교할 데이터의 바이트 수

✔️ Return

  • 두 문자열이 같으면 0반환
  • 다르면 (dest - str)값을 반환

✔️ !! Notice

  • strncmp()s1s2가 모두 NULL값이 나오면 남은 카운트에 관계없이 0을 반환한다.
  • memcpy() 두 문자열 중 하나가 널값으로 인해 끝나더라도 주어진 바이트가지 비교한다.







const

Makefile

Tester

size_t vs unsigned int

  • size_t 는 unsigned int 이며, 문자열이나 메모리의 사이즈를 나타낼 때 사용합니다. "unsigned int"를 typedef unsigned int size_t; 이렇게 size_t 라는 이름으로 정의해 놓은 것입니다.

  • size_t 는, 32비트 운영체제에서는 "부호없는 32비트 정수"이고, 64비트 운영체제에서는 "부호없는 64비트 정수"입니다.

  • 그러나 "unsigned int" 또는 "int"는, 64비트 OS라고 해서 꼭 64비트 정수는 아닙니다. 여전히 32비트일 수도 있습니다. 이것이 size_t형과 "unsigned int"형의 차이입니다.

  • 메모리문자열 등의 길이를 구할 때에는 "unsigned int" 대신 size_t 라는 형으로 길이가 반환됩니다.

etc

0개의 댓글