Exercise 00 : ft_strdup
• Reproduce the behavior of the function strdup (man strdup).
#include <stdlib.h>
char *ft_strdup(char *src)
{
char *dest;
int len;
int i;
len = 0;
while (src[len] != '\0')
len++;
dest = (char *)malloc(sizeof(char) * (len + 1));
if (dest == 0)
return (0);
i = 0;
while (i < len)
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (dest);
}
strdup함수를 구현하는 함수
strcpy는 복사 받을 dest를 매개변수로 받지만, strdup는 src만을 매개변수로 받아 동적할당을 사용하여 dest를 직접 만들고 사용하기 때문에 더 안정적이다. 하지만 free를 꼭 사용해야한다.
Exercise 01 : ft_range
• Create a function ft_range which returns an array of ints. This int array should contain all values between min and max.
#include <stdlib.h>
int *ft_range(int min, int max)
{
int *result;
int range;
int i;
range = max - min;
if (range <= 0)
return (0);
result = (int *)malloc(sizeof(int) * range);
if (result == 0)
return (0);
i = 0;
while (min < max)
result[i++] = min++;
return (result);
}
min값과 max값이 주어지면 배열에 min부터 max 이전 숫자까지 넣어줘야 한다.
Exercise 02 : ft_ultimate_range
• Create a function ft_ultimate_range which allocates and assigns an array of ints. This int array should contain all values between min and max.
#include <stdlib.h>
int ft_ultimate_range(int **range, int min, int max)
{
int *ptr;
int rg;
int i;
rg = max - min;
if (rg <= 0)
return (0);
ptr = (int *)malloc(sizeof(int) * rg);
if (ptr == 0)
return (0);
i = 0;
while (min < max)
ptr[i++] = min++;
*range = ptr;
return (rg);
}
01번과 같지만, 반환값이 max-min값이고, 01번에서 만드는 것과 같은 배열을 range라는 이중포인터를 매개변수로 받아, 그 매개변수로 해당 배열을 전달해줘야 한다. 즉 이 이중포인터는 2차원 배열이라기보다는 배열 자체의 주솟값을 사용하여 그 배열을 함수의 매개변수에 저장하는 역할을 한다.
포인터 공부는 해도해도 너무 어렵다...
Exercise 03 : ft_strjoin
• Write a function that will concatenate all the strings pointed by strs separated by sep.
#include <stdlib.h>
int str_len(char *str)
{
int len;
len = 0;
while (*str)
{
len++;
str++;
}
return (len);
}
char *concat(char *str1, char *str2)
{
int i;
int len;
i = 0;
len = 0;
while (str1[len] != '\0')
len++;
while (str2[i] != '\0')
str1[len++] = str2[i++];
str1[len] = '\0';
return (str1);
}
char *ft_strjoin(int size, char **strs, char *sep)
{
int i;
int len;
char *result;
i = 0;
len = 0;
while (i < size)
len += str_len(strs[i++]);
if (size > 0)
len += (size - 1) * str_len(sep);
result = (char *)malloc(sizeof(char) * (len + 1));
result[0] = '\0';
if (result == 0)
return (0);
i = 0;
while (i < size)
{
result = concat(result, strs[i]);
if (i < size - 1)
result = concat(result, sep);
i++;
}
result[len] = '\0';
return (result);
}
문자열로 이루어진 배열과 구분자 문자열이 주어지면, 문자열 배열에 있는 문자열 사이사이에 구분자를 집어넣어 하나의 큰 문자열을 만드는 함수
문자열을 붙여주기 전에 먼저 전체 길이를 알아야 하기 때문에 str_len함수 사용. 그리고 문자열을 이어붙여주는 concat함수 사용.
! 주의할 점
Exercise 04 : ft_convert_base
ft_convert_base.c
#include <stdlib.h>
int is_space(char c);
int base_check(char *base);
int find_base(char *base, char c);
int nbr_len(int nbr, int len);
int ft_atoi(char *str, char *base, int len)
{
int result;
int temp;
result = 0;
temp = 0;
while (*str != '\0')
{
temp = find_base(base, *str++);
if (temp < 0)
break ;
result = result * len + temp;
}
return (result);
}
int ft_atoi_base(char *nbr, char *base)
{
int num;
int sign;
int len;
num = 0;
sign = 1;
len = base_check(base);
while (is_space(*nbr))
nbr++;
while (*nbr == '-' || *nbr == '+')
{
if (*nbr == '-')
sign *= -1;
nbr++;
}
num = ft_atoi(nbr, base, len);
return (num * sign);
}
char *ft_putnbr_base(int num, char *base, char *result, int len)
{
int i;
int temp;
int base_len;
base_len = base_check(base);
if (num == 0)
result[0] = base[0];
if (num < 0)
result[0] = '-';
i = len - 1;
while (num != 0)
{
temp = num % base_len;
if (temp < 0)
temp *= -1;
result[i] = base[temp];
num /= base_len;
i--;
}
result[len] = '\0';
return (result);
}
char *ft_convert_base(char *nbr, char *base_from, char *base_to)
{
int num;
int len;
char *result;
if (base_check(base_from) < 2 || base_check(base_to) < 2)
return (0);
num = ft_atoi_base(nbr, base_from);
len = nbr_len(num, base_check(base_to));
result = (char *)malloc(sizeof(char) * (len + 1));
if (result == 0)
return (0);
result = ft_putnbr_base(num, base_to, result, len);
return (result);
}
ft_convert_base2.c
int is_space(char c)
{
char *space;
space = " \n\t\v\f\r";
while (*space != '\0')
{
if (c == *space)
return (1);
space++;
}
return (0);
}
int base_check(char *base)
{
int len;
int i;
int j;
len = 0;
i = 0;
j = 0;
while (base[len] != '\0')
{
if (is_space(base[len]) || base[len] == '-' || base[len] == '+')
return (0);
len++;
}
while (i < len - 1)
{
j = i + 1;
while (j < len)
{
if (base[i] == base[j])
return (0);
j++;
}
i++;
}
return (len);
}
int find_base(char *base, char c)
{
int i;
i = 0;
while (base[i] != '\0')
{
if (base[i] == c)
return (i);
i++;
}
return (-1);
}
int nbr_len(int nbr, int len)
{
int cnt;
cnt = 0;
if (nbr == 0)
return (1);
if (nbr < 0)
cnt++;
while (nbr != 0)
{
cnt++;
nbr /= len;
}
return (cnt);
}
base_from에 해당하는 진수인 nbr을 base_to에 해당하는 진수로 바꿔주는 함수
결국 전체 과정은 nbr(base_from) -> int -> nbr(base_to) 과정
즉 atoi_base 이후 putnbr_base를 해줘야 한다.
두 과정이 쓰는 함수가 비슷해서 파일 하나로 만드려고 고집부리다가 시간낭비함
두번째 파일에 기본적인 공백확인, base길이 및 적법성 확인, base에서 해당 index를 찾기, 마지막으로 putnbr_base할 시 필요한 문자열의 길이를 재는 nbr_len을 구현했다. nbr_len은 음수가 나올 경우 -부호를 넣어야 하므로 자리 하나를 더 추가했다.
그리고 복잡한 과정을 거치는 것 처럼 보이지만 앞서 말한 nbr에서 해당 진수의 index를 찾아 base의 길이를 곱하면서 int형으로 변환하고, 다시 변환할 base의 길이를 나누면서 그 갚의 인덱스를 결과값 배열에 뒷자리부터 추가한다.
Exercise 05 : ft_split
#include <stdlib.h>
int is_sep(char c, char *sep)
{
while (*sep != '\0')
{
if (*sep == c)
return (1);
sep++;
}
return (0);
}
char *str_dup(char *str, char *charset)
{
int len;
char *dest;
int i;
len = 0;
while (str[len] != '\0' && !is_sep(str[len], charset))
len++;
dest = (char *)malloc(sizeof(char) * (len + 1));
i = 0;
while (i < len)
{
dest[i] = str[i];
i++;
}
dest[i] = '\0';
return (dest);
}
int element_count(char *str, char *charset)
{
int cnt;
cnt = 0;
while (*str != '\0')
{
if (!is_sep(*str, charset))
{
cnt++;
while (!is_sep(*str, charset) && *str != '\0')
str++;
}
else
str++;
}
return (cnt);
}
char **ft_split(char *str, char *charset)
{
int num;
int i;
char **result;
num = element_count(str, charset);
result = (char **)malloc(sizeof(char *) * (num + 1));
if (result == 0)
return (0);
i = 0;
while (*str != '\0')
{
if (!is_sep(*str, charset))
{
result[i++] = str_dup(str, charset);
while (!is_sep(*str, charset) && *str != '\0')
str++;
}
else
str++;
}
result[i] = 0;
return (result);
}
구분자(charset)가 주어지면 해당 str을 그 구분자로 split해주는 함수
앞서 풀었던 strjoin의 반대방향이라고 생각하면 된다. 먼저 구분자를 제외한 element들의 개수를 세고, 그 개수 만큼의 문자열이 들어갈 배열, 즉 이중포인터 배열을 할당한다. 그 후 00번의 strdup와 비슷하게, 문자열의 끝이거나 구분자를 만났을 시 거기까지 복사해주는 함수를 사용한다. 마지막으로 element의 개수를 세는 방식과 유사한 방식으로 element가 나올때까지 포인터를 이동 후 복사하고, 또 나올때까지 이동하고... 를 반복한다.
개발자로서 성장하는 데 큰 도움이 된 글이었습니다. 감사합니다.