C02

김원호·2023년 7월 24일

42seoul

목록 보기
5/10

문자열 관련 함수들 구현

Exercise 00 : ft_strcpy

char	*ft_strcpy(char *dest, char *src)
{
	int	len;

	len = 0;
	while (src[len] != '\0')
	{
		dest[len] = src[len];
		len++;
	}
	dest[len] = '\0';
	return (dest);
}

src를 dest에 복사하는 함수
리턴값 : 복사된 문자열

  • dest와 src의 길이에 따른 다음과 같은 경우의 수가 있다.
  1. dest_len < src_len : runtime error
  2. dest_len = src_len : 정상적으로 복사
  3. dest_len > src_len : src가 복사되고 나머지 dest 사라짐
  • 마지막 경우의 수에 따라서 src가 다 복사되고 마지막에 null문자(\0)추가

Exercise 01 : ft_strncpy

void	*ft_strncpy(char *dest, char *src, unsigned int n)
{
	unsigned int	i;

	i = 0;
	while (i < n && src[i] != '\0')
	{
		dest[i] = src[i];
		i++;
	}
    while (i < n)
    	dest[i++] = '\0'
	return (dest);
}

src를 dest에 n만큼 복사하는 함수
src의 길이보다 크고 n보다 작은 위치는 null문자로 바꿈
리턴값 : 복사된 문자열

  • 00번과 동일하게 문자열을 복사하는데, 이 때 복사할 src의 길이 n이 주어짐
    따라서 00번과 차이점은 "n을 초과하는 원본 문자가 사라지지 않음"

  • test case
    input (dest : Howareyou | src : Hello | n : 5)
    output (Helloeyou)
    input (dest : Howareyou | src : Hello | n : 10)
    output (Hello)

Exercise 02 : ft_str_is_alpha
• Create a function that returns 1 if the string given as a parameter contains only alphabetical characters, and 0 if it contains any other character.

int	ft_str_is_alpha(char *str)
{
	int	check;
	int	i;

	check = 1;
	i = 0;
	while (str[i] != '\0')
	{
		if (str[i] >= 'a' && str[i] <= 'z')
			i++;
		else if (str[i] >= 'A' && str[i] <= 'Z')
			i++;
		else
		{
			check = 0;
			break ;
		}
	}
	return (check);
}

알파벳으로만 이루어진 문자열이면 1을, 그렇지 않으면 0을 리턴하는 함수

Exercise 03 : ft_str_is_numeric
• Create a function that returns 1 if the string given as a parameter contains only digits, and 0 if it contains any other character.

int	ft_str_is_numeric(char *str)
{
	int	i;
	int	check;

	i = 0;
	check = 1;
	while (str[i] != '\0')
	{
		if (str[i] < '0' || str[i] > '9')
		{
			check = 0;
			break ;
		}
		i++;
	}
	return (check);
}

02번과 마찬가지로 이번에는 숫자로만 이루어지면 1, 그렇지 않으면 0을 리턴하는 함수

Exercise 04 : ft_str_is_lowercase
• Create a function that returns 1 if the string given as a parameter contains only lowercase alphabetical characters, and 0 if it contains any other character

int	ft_str_is_lowercase(char *str)
{
	int	i;
	int	check;

	i = 0;
	check = 1;
	while (str[i] != '\0')
	{
		if (str[i] < 'a' || str[i] > 'z')
		{
			check = 0;
			break ;
		}
		i++;
	}
	return (check);
}

소문자로만 이루어지면 1, 그렇지 않으면 0을 리턴하는 함수

Exercise 05 : ft_str_is_uppercase
Create a function that returns 1 if the string given as a parameter contains only uppercase alphabetical characters, and 0 if it contains any other character.

int	ft_str_is_uppercase(char *str)
{
	int	i;
	int	check;

	i = 0;
	check = 1;
	while (str[i] != '\0')
	{
		if (str[i] < 'A' || str[i] > 'Z')
		{
			check = 0;
			break ;
		}
		i++;
	}
	return (check);
}

대문자로만 이루어지면 1, 그렇지 않으면 0을 리턴하는 함수

Exercise 06 : ft_str_is_printable
• Create a function that returns 1 if the string given as a parameter contains only printable characters, and 0 if it contains any other character.

int	ft_str_is_printable(char *str)
{
	int	i;
	int	check;

	i = 0;
	check = 1;
	while (str[i] != '\0')
	{
		if (str[i] < 32 || str[i] > 126)
		{
			check = 0;
			break ;
		}
		i++;
	}
	return (check);
}

출력 가능한 character로만 이루어지면 1, 그렇지 않으면 0을 리턴하는 함수

  • 출력 가능한 문자는 ascii코드 상 32~126

Exercise 07 : ft_strupcase
• Create a function that transforms every letter to uppercase.

char	*ft_strupcase(char *str)
{
	int	diff;
	int	i;

	diff = 'A' - 'a';
	i = 0;
	while (str[i] != '\0')
	{
		if (str[i] >= 'a' && str[i] <= 'z')
			str[i] += diff;
		i++;
	}
	return (str);
}

모든 문자를 대문자로 바꿔서 리턴

Exercise 08 : ft_strlowcase
• Create a function that transforms every letter to lowercase.

char	*ft_strlowcase(char *str)
{
	int	diff;
	int	i;

	diff = 'A' - 'a';
	i = 0;
	while (str[i] != '\0')
	{
		if (str[i] >= 'A' && str[i] <= 'Z')
			str[i] -= diff;
		i++;
	}
	return (str);
}

모든 문자를 소문자로 바꿔서 리턴

Exercise 09 : ft_strcapitalize
• Create a function that capitalizes the first letter of each word and transforms all other letters to lowercase.

int	check_flag(char c)
{
	if (c >= '0' && c <= '9')
		return (3);
	else if (c >= 'A' && c <= 'Z')
		return (2);
	else if (c >= 'a' && c <= 'z')
		return (1);
	else
		return (0);
}

char	*ft_strcapitalize(char *str)
{
	int	i;
	int	flag;

	i = 0;
	flag = 1;
	while (str[i] != '\0')
	{
		if (flag == 1)
		{
			flag = 0;
			if (check_flag(str[i]) == 0)
				flag = 1;
			else if (check_flag(str[i]) == 1)
				str[i] -= 32;
		}
		else
		{
			if (check_flag(str[i]) == 0)
				flag = 1;
			else if (check_flag(str[i]) == 2)
				str[i] += 32;
		}
		i++;
	}
	return (str);
}

각 단어의 첫 글자를 대문자화(capitalize)해서 리턴하는 함수

  • 주의할 점 : 대문자 자리가 아닌 자리는 다 소문자로 바꿔야 함
  • 주의할 점 : 띄어쓰기 말고 특수문자 이후도 대문자 자리임

Exercise 10 : ft_strlcpy

int	ft_strlen(char *str)
{
	int	count;

	count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return (count);
}

unsigned int	ft_strlcpy(char *dest, char *src, unsigned int size)
{
	unsigned int	i;
	unsigned int	len;

	i = 0;
	len = ft_strlen(src);
	if (!dest || !src)
		return (0);
	if (size == 0)
		return (len);
	while (src[i] != '\0' && i + 1 < size)
	{
		dest[i] = src[i];
		i++;
	}
	dest[i] = '\0';
	return (len);
}

src를 dest에 복사하는 함수...
인데 size를 매개변수로 넣고 리턴도 int값인걸 확인해야함

  • 기본적으로 strncpy는 size만큼 복사하지만 strlcpy는 size - 1만큼 복사하고 마지막에 null문자를 추가해줌 (안정성)
  • 리턴값은 복사된 src의 길이 (null 포함)
  • dest와 src가 null일 경우 0을 리턴
  • size가 0인 경우 src의 길이 리턴

Exercise 11 : ft_str_non_printable
Create a function that displays a string of characters onscreen. If this string contains characters that aren’t printable, they’ll have to be displayed in the shape of hexadecimals (lowercase), preceeded by a "backslash".

#include <unistd.h>

void	ft_putstr_non_printable(char *str)
{
	char			*hex;
	unsigned int	p;
	unsigned int	q;
	unsigned int	i;
	unsigned char	*temp;

	i = 0;
	hex = "0123456789abcdef";
	temp = (unsigned char *)str;
	while (str[i] != '\0')
	{
		if (temp[i] < 32 || temp[i] > 126)
		{
			p = temp[i] / 16;
			q = temp[i] % 16;
			write(1, "\\", 1);
			write(1, &hex[p], 1);
			write(1, &hex[q], 1);
		}
		else
			write(1, &temp[i], 1);
		i++;
	}
}

문제 설명이 복잡해보이는데 문자열에 non_printable이 있으면 그 문자를 backslash(\)와 해당 문자의 ascii를 16진수로 변환한 값으로 바꿔주기만 하면 된다 복잡하네

  • non printable은 06번에서와 같이 ascii코드로 찾으면 된다
  • 16진수로 쉽게 변환하기 위해서 배열을 이용했다.
  • ex) 13은 16진수로 hex[13] = d
  • 확장 아스키도 처리하기 위해서 입력받은 str의 자료형을 unsigned char로 바꾸어서 다루어야 한다.

Exercise 12 : ft_print_memory
• Create a function that displays the memory area onscreen.
• The display of this memory area should be split into three "columns" separated by a space:
◦ The hexadecimal address of the first line’s first character followed by a ’:’.
◦ The content in hexadecimal with a space each 2 characters and should be
padded with spaces if needed (see the example below).
◦ The content in printable characters.
• If a character is non-printable, it’ll be replaced by a dot.
• Each line should handle sixteen characters.
• If size is equal to 0, nothing should be displayed.

#include <unistd.h>

char	to_hex(int num)
{
	char	*hex;

	hex = "0123456789abcdef";
	return (hex[num]);
}

void	print_address(unsigned long long add)
{
	char	result[16];
	int		i;

	i = 0;
	while (i < 16)
	{
		result[i++] = to_hex(add % 16);
		add /= 16;
	}
	while (i > 0)
		write(1, &result[--i], 1);
	write(1, ": ", 2);
}

void	print_ascii(unsigned char *string, int len)
{
	int		i;
	char	result[32];

	i = 0;
	while (i < 32)
		result[i++] = ' ';
	i = 0;
	while (i < 16 && i < len)
	{
		result[2 * i] = to_hex(string[i] / 16);
		result[2 * i + 1] = to_hex(string[i] % 16);
		i++;
	}
	i = 0;
	while (i < 32)
	{
		write(1, &result[i++], 1);
		if (i % 4 == 0)
			write(1, " ", 1);
	}
}

void	print_word(unsigned char *string, int len)
{
	int		i;
	char	result[16];

	i = 0;
	while (i < 16)
		result[i++] = ' ';
	i = 0;
	while (i < 16 && i < len)
	{
		if (string[i] >= 32 && string[i] <= 126)
			result[i] = string[i];
		else
			result[i] = '.';
		i++;
	}
	if (len >= 16)
		write(1, result, 16);
	else
		write(1, result, len);
}

void	*ft_print_memory(void *addr, unsigned int size)
{
	unsigned int	i;
	char			*str;

	str = (char *)addr;
	i = 0;
	while (i < size)
	{
		print_address((unsigned long long)&str[i]);
		print_ascii((unsigned char *)&str[i], size - i);
		print_word((unsigned char *)&str[i], size - i);
		write(1, "\n", 1);
		i += 16;
	}
	return (addr);
}

앞에 12문제 푸는 시간에 몇 배가 걸린 12번 문제
문자열을 16자씩 나누어서 출력하는데,
3개의 칼럼으로 나눠서
메모리주소 | 아스키코드 | 해당문자
출력하고 각각은 스페이스로 구분하고, 아스키코드는 두 개 출력 후 스페이스 출력 반복, nonprintable문자는 마침표(.)로 표시...
하는 무시무시한 문제다

  • sample out
    000000010a161f40: 426f 6e6a 6f75 7220 6c65 7320 616d 696e Bonjour les amin
    000000010a161f50: 6368 6573 090a 0963 0720 6573 7420 666f ches...c. est fo
    000000010a161f60: 7509 746f 7574 0963 6520 7175 206f 6e20 u.tout.ce qu on
    000000010a161f70: 7065 7574 2066 6169 7265 2061 7665 6309 peut faire avec.
    000000010a161f80: 0a09 7072 696e 745f 6d65 6d6f 7279 0a0a ..print_memory..
    000000010a161f90: 0a09 6c6f 6c2e 6c6f 6c0a 2000 BBBB BBBB ..lol.lol. .
    -> BBBB는 이해를 돕기 위한 공백

  • 출력을 위해 4개의 함수를 추가로 구현했다.

  1. to_hex : 10진수를 넣으면 16진수 char형태로 리턴해주는 함수, 16미만의 수를 넣어야 함
  2. print_address : 문자열 주솟값을 출력하는 함수
  3. print_ascii : 해당 문자의 ascii코드를 출력하는 함수
  4. print_word : 문자열을 출력하는 함수
  • 가장 신경써야 할 부분은 문자 중간에 null문자가 들어간 경우에 문자열의 끝이라고 판단하지 않아야 했다. 그래서 2번과 3번은 문자열의 길이를 매개변수로 만들었다.
  • 11번과 마찬가지로 확장ascii를 처리하기 위해서 unsigned char 자료형을 이용해야 함
  • word를 출력할 때 주어진 size를 초과하는 부분을 그냥 빈 공백으로 출력했는데 그렇게 했을 때 오류가 남

0개의 댓글