blackhole 1st step
: ptr
위치부터 num
개의 바이트 만큼 value
로 초기화
void *ft_memset(void *ptr, int value, size_t num)
{
unsigned char *new;
unsigned char src;
size_t i;
new = ptr;
src = value;
i = 0;
while (i++ < num)
*new++ = src;
return (ptr);
}
✏️ 포인터, 설정할 값, 크기
✏️ 원하는 특정 값으로 메모리 세팅 - 메모리의 내용을 모두 0으로 만들 때 주로 사용
✏️ value
: 인자가 int
로 전달되지만 함수 내부적으로 unsigned char
(1 바이트)로 형변환되어 사용
✏️ memset
함수에 설정할 크기를 지정할 때 보통 숫자 대신 sizeof
를 사용
char *cPtr = malloc(sizeof(char)); // char의 크기 1바이트만큼 동적 메모리 할당
memset(cPtr, 0, sizeof(char)); // char의 크기 1바이트만큼 0으로 설정(올바른 방법)
memset(cPtr, 0, sizeof(char *)); // 32비트: char 포인터의 크기 4바이트만큼 0으로 설정(잘못된 방법)
// 64비트: char 포인터의 크기 8바이트만큼 0으로 설정(잘못된 방법)
free(cPtr);
: s
의 위치부터, n
개의 바이트 만큼 0
으로 초기화
void ft_bzero(void *s, size_t n)
{
unsigned char *dst;
size_t i;
dst = s;
i = 0;
while (i++ < n)
*dst++ = 0;
}
✏️ 메모리를 0으로 세팅
: src
가 가리키는 곳 부터 n
바이트 만큼을 dst
가 가리키는 곳에 복사
void *ft_memcpy(void *dst, const void *src, size_t n)
{
unsigned char *new_dest;
unsigned char *new_src;
size_t i;
if (!dst && !src)
return (0);
new_dest = dst;
new_src = (unsigned char *)src;
i = 0;
while (i++ < n)
*new_dest++ = *new_src++;
return (dst);
}
✏️ src
의 null
문자를 검사하지 않음 → 언제나 정확히 n
바이트 만큼 복사
: n
바이트의 데이터를 dst
에 복제할 때, 데이터에서 문자 c
를 만나면 c
까지 복제하고 복제 중단
void *ft_memccpy(void *dst, const void *src, int c, size_t n)
{
size_t i;
int flag;
i = 0;
flag = 0;
while (i < n && ((unsigned char *)src)[i] && !flag)
{
flag = ((unsigned char *)src)[i] == ((unsigned char)c) ? 1 : 0;
i++;
}
if (flag)
{
ft_memcpy(dst, src, i);
return (dst + i);
}
else
{
ft_memcpy(dst, src, n);
return (0);
}
}
ft_memccpy : 1.OK 2.OK 3.OK 4.KO 5.OK 6.OK 7.OK
LibftTest
에서 오류 떴다..void *ft_memccpy(void *dst, const void *src, int c, size_t n)
{
char *ptr1;
unsigned char *ptr2;
size_t i;
if (!dst && !src)
return (0);
ptr1 = dst;
ptr2 = (unsigned char *)src;
i = 0;
while (i < n)
{
ptr1[i] = ptr2[i];
if (ptr2[i] == (unsigned char)c)
return (dst + i + 1);
i++;
}
return (NULL);
}
✏️ 복제된 dst
에서 복제가 끝난 다음 번지를 return
✏️ n
바이트 만큼 중 c
를 찾지 못하면 NULL
값 반환
: src
메모리 영역에서 dest
메모리 영역으로 n
바이트 만큼 복사한다. 이 때, src
배열은 src
와 dest
의 메모리 영역과 겹치지 않는 메모리 영역부터 먼저 복사한다.
void *ft_memmove(void *dst, const void *src, size_t n)
{
unsigned char *s;
unsigned char *d;
if (dst == src || !n)
return (dst);
s = (unsigned char *)src;
d = (unsigned char *)dst;
if (dst < src)
{
while (n--)
*d++ = *s++;
}
else
{
while (n--)
*(d + n) = *(s + n);
}
return (dst);
}
✏️ 복사하는 기능을 가진 함수
✏️ memcpy
와의 차이점:
memcpy()
는 버퍼를 거치지 않고 (빠르다는 장점)
memmove()
는 버퍼를 이용한다. (안전하다는 장점 - 메모리가 겹치지 않음)
위 코드는 버퍼를 쓰지 않음 ㅎ
✏️ dst > src
인 경우:
src
시작 주소가 dest
시작 주소보다 앞에 있을 때, 오버랩의 가능성 → 뒤에서 부터 한 바이트씩 복사
: ptr
이 가리키는 메모리 처음부터 n
바이트 까지 탐색하면서 처음으로 c
와 일치하는 값의 주소 리턴
void *ft_memchr(const void *s, int c, size_t n)
{
unsigned char *ptr;
ptr = (unsigned char *)s;
while (n--)
{
if (*ptr != ((unsigned char)c))
ptr++;
else
return (ptr);
}
return 0;
}
✏️ c
는 int로 값이 전달되나, 한 바이트씩 비교하기 때문에 unsigned char
로 변환되어 사용
✏️ 값을 찾지 못한다면 NULL 을 리턴한다.
: ptr1
이 가리키는 처음 num
바이트의 데이터와 ptr2
가 가리키는 처음 num
바이트의 데이터를 비교한다.
int ft_memcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char *ptr1;
const unsigned char *ptr2;
if (!n)
return (0);
ptr1 = (unsigned char *)s1;
ptr2 = (unsigned char *)s2;
while (n--)
{
if (*ptr1 != *ptr2)
return (*ptr1 - *ptr2);
ptr1++;
ptr2++;
}
return (0);
}
✏️ 두 개의 메모리 블록을 비교
✏️ 두 메모리 블록이 정확히 같다면 → 0 을 리턴
✏️ 두 메모리 블록이 다를 경우 → 그 값이 ptr1
이 더 크면 0 보다 큰 값을 아니면 0 보다 작은 값을 리턴
(ptr1
과 ptr2
가 가리키는 메모리 블록에서 앞에서 부터 처음으로 다른 바이트를 살펴 보는데, 그 바이트를 unsigned char
로 해석 하였을 때)
✏️ strncmp
와의 차이점
-memcmp
: 두 문자열 중 하나가 끝나더라도 상관없이 서로 다른 값이 나오거나, n개가 될 때 까지 비교 수행
-strncmp
: s1과 s2가 모두 NULL
값이 나오면 남은 카운트에 관계없이 0 반환
-예) a[20] "abcde"
, b[20] "abcde"
가 있을 때 memcmp
는 쓰레기 값까지 비교를 하게된다.
: 문자열의 길이를 구함
size_t ft_strlen(const char *str)
{
size_t i;
i = 0;
while (str[i] != '\0')
i++;
return (i);
}
: src
를 dsc
에 null
을 포함해서 (size-1)
개 까지 복사 후 마지막에 null
을 붙여줌
size_t ft_strlcpy(char *dst, const char *src, unsigned int size)
{
size_t src_len;
size_t i;
if (!dst || !src)
return (0);
src_len = 0;
while (src[src_len] != '\0')
{
src_len++;
}
if (size == 0)
{
return (src_len);
}
i = 0;
while (src[i] != '\0' && i < (size - 1))
{
dst[i] = src[i];
i++;
}
dst[i] = '\0';
return (src_len);
}
✏️ null
을 보장하여 문자열 복사
✏️ src
의 길이가 size
보다 작으면 → 부족한 부분을 null
로 채움
추가해야함 [💥 ]
if (!dst || !src)
return (0);
: dst
의 길이를 포함해서 새로운 dst
의 길이를 설정하고 (size
)
빈 공간 만큼 src
를 이어붙인다. 마지막에 null
을 보장하여 넣어준다.
size_t ft_strlcat(char *dst, const char *src, unsigned int size)
{
size_t i;
size_t dest_len;
size_t src_len;
dest_len = ft_strlen(dst);
src_len = ft_strlen(src);
i = 0;
if (size < dest_len + 1)
return (size + src_len);
if (size > dest_len + 1)
{
while (src[i] != '\0' && dest_len + 1 + i < size)
{
dst[dest_len + i] = src[i];
i++;
}
}
dst[dest_len + i] = '\0';
return (dest_len + src_len);
}
✏️ null
을 보장하여 문자열 이어붙이기
✏️ size
= dst
길이 + 붙일 데이터 길이 + NULL
✏️ 리턴값
size
< strlen(dst)
: strlen(src)
+ size
size
> strlen(dst)
: strlen(src)
+ strlen(dst)
: 문자열 s
에서 첫 번째로 찾은 문자 c
의 포인터를 리턴
char *ft_strchr(const char *str, int c)
{
char find;
int i;
i = 0;
find = (unsigned char)c;
while (str[i] != '\0')
{
if (str[i] == find)
return ((char *)str + i);
i++;
}
if (str[i] == find)
return ((char *)str + i);
return (0);
}
✏️ 문자열에서 특정한 문자가 가장 먼저 나타나는 곳의 위치 리턴
✏️ c
는 int
형태로 형변환 되어서 전달되지만 함수 내부적으로는 다시 char
형태로 처리됨
✏️ 만일 문자가 없다면 NULL
포인터 리턴
: big
의 처음부터 n
까지 little
문자열이 포함되어있는지 검색, 가장 먼저 발견된 위치 리턴
char *ft_strnstr(const char *str, const char *to_find, size_t len)
{
size_t i;
size_t j;
i = 0;
if (to_find[0] == '\0')
return ((char *)str);
while (str[i] && i < len)
{
j = 0;
while ((str[i] == to_find[j] || to_find[j] == '\0') && i < len)
{
i++;
j++;
if (to_find[j] == '\0')
return ((char *)&str[i - j]);
}
i++;
}
return (NULL);
}
LibtTester
에서 오류 .. ft_strnstr : 1.OK 2.KO 3.OK 4.OK 5.OK 6.OK 7.OK 8.OK 9.OK 10.KO 11.OK 12.OK
char *ft_strnstr(const char *big, const char *little, size_t n)
{
size_t i;
size_t j;
size_t little_len;
i = 0;
little_len = ft_strlen(little);
if (!little_len)
return ((char *)big);
while (big[i] && i + little_len <= n)
{
if (big[i] == little[0])
{
j = 0;
while (big[i + j] && little[j])
{
if (big[i + j] != little[j])
break ;
else if (j == little_len - 1)
return ((char *)big + i);
j++;
}
}
i++;
}
return (NULL);
}
✏️ 문자열 내에서 부분문자열 탐색
✏️ 검색에서 마지막 null
문자는 포함하지 않음
✏️ 만약 little
이 발견되지 않는다면 null
을 리턴
✏️ little
이 null
이면 big
을 그대로 반환
✏️ big
의 문자열 길이 혹은 n
보다 little
의 문자열 길이가 더 길면 null
반환
: 두 문자열의 처음부터 n
까지만 정확히 일치하는지 비교
int ft_strncmp(char *s1, char *s2, unsigned int n)
{
while (*s1 != '\0' && *s2 != '\0' && n > 0)
{
if (*s1 != *s2)
break;
s1++;
s2++;
n--;
}
if (n == 0)
return (0);
return (*(unsigned char *)s1 - *(unsigned char *)s2);
}
✏️ 일치하면 0
반환, 일치하지 않으면 (s1[i]-s2[i])
차이값 리턴
이런 const를 빼먹었군
int ft_strncmp(const char *s1, const char *s2, unsigned int n)
: 문자열을 정수(int
)로 변환
int ft_is_space(const char c)
{
if (c == ' ' || (c >= 9 && c <= 13))
return (1);
else
return (0);
}
int ft_check_str(const char c, const char *str)
{
while (*str)
{
if (*str == c)
return (1);
str++;
}
return (0);
}
int ft_atoi(const char *str)
{
int sign;
unsigned long long result;
int i;
sign = 1;
result = 0;
i = 0;
while (*str != 0 && ft_is_space(*str))
str++;
if (ft_check_str(*str, "+-") != 0)
{
if (*str == '-')
sign *= -1;
str++;
}
while (str[i] != '\0' && str[i] >= '0' && str[i] <= '9')
{
result = result * 10 + (str[i] - '0');
i++;
}
if (result > 9223372036854775807)
return (sign == '-' ? 0 : -1);
return (sign * result);
}
libft-unit-test
오류 #include <limits.h>
추가하고 while (str[i] != '\0' && str[i] >= '0' && str[i] <= '9')
{
result = result * 10 + (str[i] - '0');
if (!(INT_MIN <= result * sign && result * sign <= INT_MAX))
return ((sign < 0) ? 0 : -1);
i++;
}
이렇게 수정하니까 OK
되긴하는데 딱히 필요없는 과정이 아닌가.. 싶음#include <limits.h>
int ft_is_space(const char c)
{
if (c == ' ' || (c >= 9 && c <= 13))
return (1);
else
return (0);
}
int ft_check_str(const char c, const char *str)
{
while (*str)
{
if (*str == c)
return (1);
str++;
}
return (0);
}
int ft_atoi(const char *str)
{
int sign;
long long result;
int i;
sign = 1;
result = 0;
i = 0;
while (ft_is_space(*str))
str++;
if (ft_check_str(*str, "+-") != 0)
{
if (*str == '-')
sign *= -1;
str++;
}
while (str[i] != '\0' && str[i] >= '0' && str[i] <= '9')
{
result = result * 10 + (str[i] - '0');
if (!(INT_MIN <= result * sign && result * sign <= INT_MAX))
return ((sign < 0) ? 0 : -1);
i++;
}
return (sign * result);
}
int ft_isalpha(int c)
{
return (((65 <= c) && (90 >= c)) || ((97 <= c) && (122 >= c)));
}
int ft_isdigit(int c)
{
return (c >= '0' && c <= '9');
}
int ft_isalnum(int c)
{
if (c >= 'a' && c <= 'z')
return (1);
if (c >= 'A' && c <= 'Z')
return (1);
if (c >= '0' && c <= '9')
return (1);
return (0);
}
int ft_isascii(int c)
{
return (c >= 0 && c <= 127);
}
int ft_isprint(int c)
{
return (c >= 32 && c <= 126);
}
int ft_toupper(int c)
{
if (c >= 97 && c <= 122)
c -= 32;
return (c);
}
int ft_tolower(int c)
{
if (c >= 65 && c <= 90)
c += 32;
return (c);
}
: malloc
으로 할당된 공간의 값을 모두 0
으로 초기화
void *ft_calloc(size_t cnt, size_t size)
{
void *ptr;
ptr = malloc(size * cnt);
if (ptr == 0)
return (0);
ft_memset(ptr, 0, size * cnt);
return (ptr);
}
✏️ malloc
은 할당된 공간의 값을 바꾸지 않는다
: 문자열 str
길이 +1
크기를 malloc
으로 할당 후 문자열 str
을 복사한 후 반환
char *ft_strdup(const char *s)
{
size_t i;
char *res;
res = (char *)malloc(sizeof(char) * (ft_strlen(s) + 1));
if (!res)
return (0);
i = 0;
while (s[i])
{
res[i] = s[i];
i++;
}
res[i] = 0;
return (res);
}
✏️ 문자열을 새로운 메모리에 할당하여 복사
✏️ malloc
+ strcpy