Exercise 00: libft
Create your ft library. It’ll be called libft.a. A shell script called libft_creator.sh will compile source files appropriately and will create your library.
Allowed Function: write
첫 번째 문제는 library인 libft를 만드는 shell script를 작성하는 문제이다. 우선 기본적으로 library 파일은 .a 확장자를 지녔으므로 우리의 목표는 .c 파일들을 활용해서 하나의 .a 파일을 만드는 것이다.
주어진 c 파일들도 모두 직접 만들어야 하지만, 앞선 프로젝트들에서 다 만들어두었던 함수들이므로 따로 언급하지 않겠다. 아무튼 그 c파일들을 모두 flag와 함께 컴파일하여 o파일들을 만들고, 다시 그 o파일들을 활용하여 libft.a 파일을 만든다. 이때는 library를 만드는 ar command를 사용한다. 여기서 r 옵션을 추가했는데, 이는 새로운 오브젝트 파일이면 추가하고 기존 파일이면 치환한다는 의미의 옵션이다. 사실 이 옵션을 왜 추가했었는지는 잘 기억이 나지 않지만, 없이 돌렸을 때 뭔가 문제가 생겼었던 걸로 기억한다.
cc -c -Wall -Wextra -Werror ft_putchar.c ft_swap.c ft_putstr.c ft_strlen.c ft_strcmp.c
ar r libft.a ft_putchar.o ft_swap.o ft_putstr.o ft_strlen.o ft_strcmp.o
Exercise 01: Makefile
Create the Makefile that’ll compile a library libft.a.
- The Makefile will get its source files from the "srcs" directory.
- The Makefile will get its header files from the "includes" directory.
- .o files should be near their .c file.
- The Makefile should also implement the following rules: clean, fclean, re, all and of course libft.a.
Allowed Function: None
두 번째 문제는 앞서 shell을 통해 했던 라이브러리 만들기를 makefile로 수행하는 것이다. 조건이 많았지만 주요한 조건만 기재해 두었으므로, 더 자세한 조건은 subject 파일을 참고하기 바란다.
우선 변수부터 소개해보면, 모두 대문자로 보통 설정한다. CC는 컴파일러를 의미한다. 42에서는 주로 cc를 사용하므로 cc로 설정해준다. 그리고 조건에 기재된 flag들을 FLAGS 변수에 저장해 주고, 소스파일들이 srcs 디렉토리에 저장되어 있으므로 SRC_DIR 변수에, 헤더파일들은 includes 디렉토리에 있으므로 include 옵션까지 포함한 -Iincludes/를 INCLUDE 변수에 저장해 준다.
다음으로 SRCS에 소스파일 이름들을 전부 저장해 주고, OBJECTS에는 이 소스파일들을 .o 확장자로 바꿔준 오브젝트 파일 이름들을 모두 저장해 준다. 다음으로 OBJS에서는 이 오브젝트 파일들이 조건에서 기재된 대로 .c 확장자 파일들과 같은 위치에 저장될 수 있도록 SRC_DIR에 저장된 디렉토리를 OBJECT에 함께 설정해줘서 저장해준다. 마지막으로 TARGET 변수에는 결과적으로 만들어질 파일의 이름을 저장해준다.
이렇게 변수를 모두 지정했으면 이를 바탕으로 컴파일을 하는 커맨드들을 작성해 주면 된다. 여기서는 문제에서 제시한 대로 총 4가지의 명령어를 설정했다. all, clean, fclean, re가 그 네 가지이다. 이때 콜론 앞 쪽에 오는 요소들은 아래 커맨드들로 만들어낼 결과물에 해당하고, 콜론 뒤쪽에 오는 요소들은 결과물을 만들어내기 위해서 이용할 요소들이다.
첫 번째로, all 명령어는 소스파일로 오브젝트 파일을 만들고 오브젝트 파일로 타겟 파일을 만드는 과정이다. 타겟 변수에 명시된 이름의 파일을 만들 것이라는 것을 all 다음에 미리 기재해 주고, 소스 파일을 이용하여 오브젝트 파일을 먼저 만든다. 이때 커맨드에 앞서 설정한 compiler, flags 그리고 헤더 파일까지 모두 포함해 준다. -c 옵션으로 오브젝트 파일을 만드는 조건을 주고, -o로 파일 이름을 각각에 맞게 설정한다는 조건을 준다. 이때 $^의 경우 바로 윗 줄에 콜론 뒷부분에 있는 요소, 즉 결과물을 위해 이용할 요소들을 가리키고, $@의 경우 콜론 앞부분에 있는 요소, 즉 결과물을 가리킨다. 다음으로
CC = cc
FLAGS = -Wall -Wextra -Werror
SRC_DIR = ./srcs
INCLUDE = -Iincludes/
SRCS = ft_putchar.c ft_swap.c ft_putstr.c ft_strlen.c ft_strcmp.c
OBJECTS = $(SRCS:.c=.o)
OBJS = $(patsubst %.o, $(SRC_DIR)/%.o, $(OBJECTS))
TARGET = libft.a
all : $(TARGET)
$(SRC_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) $(FLAGS) $(INCLUDE) -c $^ -o $@
$(TARGET) : $(OBJS)
ar rcs $@ $^
clean:
rm -f $(OBJS)
fclean: clean
rm -f $(TARGET)
re : fclean all
.PHONY: all clean fclean re
Exercise 02: ft_split
Create a function that splits a string of character depending on another string of characters.
- You’ll have to use each character from the string charset as a separator.
- The function returns an array where each box contains the address of a string wrapped between two separators.
- The last element of that array should equal to 0 to indicate the end of the array.
- The string given as argument won’t be modifiable.
Allowed Function: None
세 번째 문제는 주어진 문자열 str을, 주어진 문자열 charset에 있는 문자들을 기준으로 나누어서 리턴하는 함수이다. 각 문자열들은 charset 문자들로 둘러싸여 있는 문자열이므로, charset 문자들, 즉 기준이 되는 문자들은 포함하지 않는다. 그리고 문자열 배열의 마지막 요소를 0으로 주어, 배열의 끝을 알려주어야 한다.
어떤 함수들로 구성되어 있는지부터 살펴보면, 문자 하나가 charset 문자열에 포함된 문자인지 확인하는 is_charset() 함수, 문자열의 길이를 리턴하는 ft_strlen() 함수, source 문자열을 destination에 복사하는 ft_strcpy() 함수, 나눠진 문자열 하나를 리턴하는 create_string() 함수의 4개의 helper function과 문자열 str과 charset을 받아 앞서 언급된 helper function들을 적절히 활용하여 문제에서 제시한 역할을 수행해 내는 ft_split() 함수로 구성된다.
ft_split() 함수를 보면, 우선 res라는 2차원 배열을 선언하여 여기에 str의 길이에 + 1 한 만큼의 크기의 메모리를 할당해 준다. 이 res 배열에는 결과물인 나눠진 문자열들이 저장될 것이다. 정확하게 몇 개로 문자열이 나눠지게 될지 알 수 없으므로, 안전하게 최대로 나눠질 수 있는 개수보다 큰 값으로 설정해 둔다.그리고 만약 입력받은 str 문자열이 빈 문자열이라면, res 문자열에 문제에서 마지막 요소에 저장되어 있어야 한다고 한 0을 저장한 후 res 배열을 리턴한다.
이렇게 기초적인 작업들을 마치고 나서는 str 문자열 전체를 순회하며, charset에 포함된 문자가 아닌 문자를 만났을 때, res 배열의 index i에 create_string()으로 나눠진 문자열 하나를 저장해 주고, 해당 문자열의 길이만큼 str을 순회하는 위치를 넘겨준 후, 다시 순회를 재개한다. 이때 index i는 현재까지 저장된 문자열들의 개수를 나타내기 위해, while문 시작 전 0으로 설정되어, 문자열이 하나씩 저장될 때마다 1씩 더해진다. 순회를 마쳤다면, 마지막 요소로 0을 저장해주고 res 배열을 리턴해주며 함수가 마무리된다.
다음으로 문자열 하나하나를 생성해 주는 creat_string() 함수를 보면, 우선 현재 위치에서 다음 charset 문자가 나오기까지의 길이(len 변수)를 파악하여, 이 길이만큼 res 문자열에 메모리를 할당해 준다. 그리고는 앞서 측정한 길이만큼을 다시 반복하며 str 문자열 내의 문자를 res 배열에 복사해 주고, 마지막으로 null character까지 추가해 준다. 그리고 이 res 문자열, 즉 나눠진 문자열을 리턴한다.
#include <stdlib.h>
int is_charset(char c, char *charset)
{
if (!(*charset))
return (0);
while (*charset)
{
if (c == *charset)
return (1);
charset++;
}
return (0);
}
int ft_strlen(char *str)
{
int len;
len = 0;
while (str[len])
len++;
return (len);
}
void ft_strcpy(char *des, char *src)
{
while (*src)
{
*des = *src;
des++;
src++;
}
}
char *create_string(char *str, char *charset)
{
int len;
char *res;
int i;
len = 0;
while (str[len] && !(is_charset(str[len], charset)))
len++;
res = (char *)malloc((len + 1) * sizeof(char));
if (res == NULL)
return (NULL);
i = 0;
while (i < len)
{
res[i] = str[i];
i++;
}
res[i] = 0;
return (res);
}
char **ft_split(char *str, char *charset)
{
char **res;
int i;
res = (char **)malloc(ft_strlen(str) * sizeof(char *));
if (!res)
return (0);
if (!(*str))
{
res[0] = 0;
return (res);
}
i = 0;
while (*str)
{
if (!is_charset(*str, charset))
{
res[i] = create_string(str, charset);
str += ft_strlen(res[i++]);
}
else
str++;
}
res[i] = 0;
return (res);
}
/*
#include <stdio.h>
int main(void)
{
int i = 0;
char **str = ft_split("", "");
while (str[i] != 0)
{
printf("%s\n", str[i]);
free(str[i]);
i++;
}
}
*/
'Hive Helsinki [42 Helsinki]' 카테고리의 다른 글
[Hive Helsinki / Piscine] BSQ (0) | 2024.05.13 |
---|---|
[Hive Helsinki / Piscine] C08 (1) | 2024.05.01 |
[Hive Helsinki / Piscine] Rush02 (0) | 2024.04.30 |
[Hive Helsinki / Piscine] C07 (1) | 2024.04.26 |
[Hive Helsinki / Piscine] C06 (1) | 2024.04.19 |