개발 프로젝트/Hive Helsinki [42 Helsinki]

[Hive Helsinki / Piscine] C06

iinana 2024. 4. 19. 03:18
728x90

  C06의 경우 대체로 터미널로부터 입력을 받는 '프로그램'을 작성할 것을 요구한다. 따라서 이전에 요구된 프로토타입의 함수만을 포함했던 것과는 달리, 이 과제에서는 바로 실행 가능한 main 함수를 포함해야 한다. 

 우선 기본적으로 터미널로부터 입력받는 방법을 알아야 하는데, 이는 main 함수의 인자를 이용한다.

int main(int argc, char **argv)

 

 위와 같은 방식으로 사용되는데, int 타입의 argc는 입력받은 parameter의 개수이고, argv는 입력받은 parameter를 문자열로 저장한 것의 배열이다. argv가 two pointer인 이유는 문자열 자체가 이미 문자의 배열인데, argv는 문자열의 배열이 되어야 하기 때문이다. 만약 터미널에 아래와 같이 입력한다고 해보자.

./a.out param1 param2

 

 이렇게 되면 argc와 argv의 값은 아래와 같아진다.

argc = 3                            // 프로그램 이름을 포함한 입력된 parameter 개수
argv[0] = "./a.out"       // 프로그램 이름
argv[1] = "param1"    // 첫 번째 parameter
argv[2] = "param2"    // 두 번째 parameter

 

 이러한 정보만 알고 나면 C06의 문제들은 오히려 다른 프로젝트 내 문제들보다 쉽게 해결이 가능하다. 

 

 

 

 Exercise 00: ft_print_program_name 

Create a program that displays its own name.
Allowed Function: write

 

 첫 번째 문제의 경우 입력된 프로그램의 내용을 출력하는 것이 과제이다. 앞서 언급했듯, argv[0]에는 프로그램 이름이 저장된다. 따라서 argv[0] 문자열을 출력하기만 하면 된다. 

#include <unistd.h>

int	main(int argc, char **argv)
{
	char	*c;

	if (argc < 1)
		return (1);
	c = argv[0];
	while (*c)
		write(1, c++, 1);
	write(1, "\n", 1);
	return (0);
}

 

 

 

 Exercise 01: ft_print_params 

Create a program that displays its given arguments. One per line, in the same order as in the command line. It should display all arguments, except for argv[0].
Allowed Function: write

 

  두 번째 문제의 경우, 프로그램 이름 즉 argv[0]를 제외한 나머지 parameter를 출력하면 된다. argc 개의 parameter가 있으므로 index 0을 제외하고 index 1부터 argc-1까지, argc-1개의 문자열을 출력하면 된다. 

#include <unistd.h>

int	main(int argc, char **argv)
{
	int		i;
	char	*a;

	i = 1;
	while (i < argc)
	{
		a = argv[i];
		while (*a)
		{
			write(1, a, 1);
			a++;
		}
		write(1, "\n", 1);
		i++;
	}
}

 

 

 

 Exercise 02: ft_rev_params 

Create a program that displays its given arguments. One per line, in the reverse order of the command line. It should display all arguments, except for argv[0].
Allowed Function: write

 

  세 번째 문제는 두 번째 문제와 유사하지만 parameter의 순서를 입력받은 것과 반대로 출력하면 된다. 따라서 while 문을 argc-1에서 시작해서 1로 끝나는 것으로 쓰면 된다.

#include <unistd.h>

int	main(int argc, char **argv)
{
	char	*c;

	while (argc > 1)
	{
		argc--;
		c = argv[argc];
		while (*c)
			write(1, c++, 1);
		write(1, "\n", 1);
	}
}

 

 

 

 Exercise 03: ft_sort_params 

Create a program that displays its given arguments sorted by ascii order. One per line, in the reverse order of the command line. It should display all arguments, except for argv[0].
Allowed Function: write

 

  네 번째 문제는 앞 두 문제와 동일하지만 아스키코드 순서를 기준으로 parameter를 정렬하여 출력해야 한다. 내가 정렬을 위해 선택한 방식은 아스키코드가 가장 작은 값을 먼저 출력하고 삭제하는 것을 계속 반복하는 것이다. 즉, 최솟값 출력 -> 최소값 삭제를 모든 요소를 출력할 때까지 반복한다. 지금 보니 코드가 조금 조잡한 것 같고, 시간 복잡도도 O(N^2)으로 효율적인 코드는 아니지만 그래도 나름 완성했었다. 

 우선 ft_strcmp() 함수는 s1 문자열과 s2 문자열을 비교해서, 두 문자열이 같으면 0을, s1이 더 크면(아스키코드 기준 더 뒷순서)  양수를 s2가 더 크면 음수를 리턴한다. ft_putstr() 함수는 문자열 출력을 위한 함수이다. 

 메인 함수에서 이중 while문을 통해 구현하는데, 바깥 while문은 max값을 출력하는 과정을 argc-1번 반복하기 위함이고, 내부 while문은 max값을 찾기 위함이다.

 내부 while문 이전에 설정되는 loc 변수는 최솟값(순서가 가장 먼저인 값)이 저장된 위치를 기록해 두기 위함이고, j는 순회하면서 loc을 찾기 위함이고, c는 최소값인 문자열을 기록해두기 위함이다. 내부 while문을 돌면서, *c가 -1(이미 출력 후 삭제되었다는 의미)이거나, 현재 확인 중인 값인 argv[j]가 더 작다면, loc을 j로 바꿔주고, c를 argv[j]로 바꿔줘야 한다. (c를 바꾸는 과정을 if문 바깥에 적은 것은 25줄 제한 때문이다.)

 이렇게 내부 while문을 통해 최솟값을 찾고 나면, 이를 출력하고 배열값을 -1로 대체하여 삭제해 준다. 배열에서 실제로 삭제하려면 인덱스가 뒷순서인 값들을 하나씩 당겨와줘야 하므로 효율이 크게 떨어진다. 따라서 사용되지 않는 다른 값으로 배열값을 대체해 주어 삭제하는 것이 더 낫다. 

#include <unistd.h>

int	ft_strcmp(char *s1, char *s2)
{
	while (*s1 && *s2)
	{
		if (*s1 != *s2)
			return (*s1 - *s2);
		s1++;
		s2++;
	}
	return (*s1 - *s2);
}

void	ft_putstr(char *str)
{
	while (*str)
		write(1, str++, 1);
	write(1, "\n", 1);
}

int	main(int argc, char **argv)
{
	int		i;
	int		j;
	int		loc;
	char	*c;

	if (argc <= 1)
		return (0);
	i = 1;
	while (i < argc)
	{
		loc = 1;
		j = 2;
		c = argv[loc];
		while (j < argc)
		{
			if ((*c == -1) || (argv[j][0] != -1 && (ft_strcmp(c, argv[j]) > 0)))
				loc = j;
			j++;
			c = argv[loc];
		}
		ft_putstr(c);
		argv[loc][0] = -1;
		i++;
	}
}
728x90