안녕하세요!
이번 글에서는 42서울 c02 과제에 포함된 함수들을 하나씩 짚어보면서, C언어의 문자열 처리 방식과 메모리 다루는 방법을 정리해보려 합니다.
c02 과제는 단순히 문자열을 출력하거나 변환하는 것처럼 보이지만,
포인터, ASCII, 반복문, 조건문, 메모리 출력 포맷, 함수 재사용까지 다양한 내용을 담고 있습니다.

✅ ft_strcpy — 문자열 복사의 기본
가장 기초적인 문자열 복사 함수입니다. src 문자열을 문자 하나씩 반복하면서 dest 배열에 복사합니다.
문자열의 끝은 반드시 \0 널 문자로 처리해야 하며, 배열의 크기를 넘지 않도록 조심해야 합니다.
char *ft_strcpy(char *dest, char *src)
{
int i = 0;
while (src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (dest);
}
✅ ft_strncpy — 복사 길이를 제한한 버전
ft_strcpy와 달리, n개까지만 복사하고 나머지는 \0으로 채우는 함수입니다.
이 함수는 실제로 라이브러리에서도 사용되는 방식으로, 안전한 복사를 연습할 수 있습니다.
char *ft_strncpy(char *dest, char *src, unsigned int n)
{
unsigned int i = 0;
while (i < n && src[i])
{
dest[i] = src[i];
i++;
}
while (i < n)
{
dest[i] = '\0';
i++;
}
return (dest);
}
✅ ft_str_is_alpha — 알파벳 판별
문자열이 알파벳으로만 이루어져 있는지 검사합니다.
문자 하나씩 확인하며, 대문자(AZ) 또는 소문자(az)에 해당하지 않으면 바로 0을 반환합니다.
int ft_str_is_alpha(char *str)
{
if (*str == '\0')
return (1);
while (*str)
{
if ((*str < 'a' || *str > 'z') && (*str < 'A' || *str > 'Z'))
return (0);
str++;
}
return (1);
}
✅ ft_str_is_numeric — 숫자인지 판별
문자열이 숫자(0~9)로만 구성되어 있는지 확인합니다.
int ft_str_is_numeric(char *str)
{
int i = 0;
while (str[i])
{
if (str[i] < '0' || str[i] > '9')
return (0);
i++;
}
return (1);
}
✅ ft_str_is_lowercase — 소문자 판별
소문자로만 구성되어 있다면 1을, 아니라면 0을 반환합니다.
int ft_str_is_lowercase(char *str)
{
int i = 0;
if (!str[0])
return (1);
while (str[i])
{
if (str[i] < 'a' || str[i] > 'z')
return (0);
i++;
}
return (1);
}
✅ ft_str_is_uppercase — 대문자 판별
대문자로만 구성되어 있는지 확인합니다.
int ft_str_is_uppercase(char *str)
{
int i = 0;
while (str[i])
{
if ((str[i] < 'A') || (str[i] > 'Z'))
return (0);
i++;
}
return (1);
}
✅ ft_str_is_printable — 출력 가능한 문자만 있는지 확인
ASCII에서 출력 가능한 문자 범위(32~126) 안에 있는 문자로만 구성되어 있는지 검사합니다.
int ft_str_is_printable(char *str)
{
while (*str)
{
if (*str < 32 || *str > 126)
return (0);
str++;
}
return (1);
}
✅ ft_strupcase — 문자열을 대문자로 변환
알파벳 중 소문자만 골라서 대문자로 바꿔줍니다. ASCII 코드에서 'a' ~ 'z'는 97 ~ 122 범위이며,
여기서 32를 빼면 대응되는 대문자가 됩니다.
char *ft_strupcase(char *str)
{
int i = 0;
while (str[i])
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
return (str);
}
✅ ft_strlowcase — 문자열을 소문자로 변환
대문자에만 32를 더해서 소문자로 바꿉니다.
char *ft_strlowcase(char *str)
{
int i = 0;
while (str[i])
{
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] += 32;
i++;
}
return (str);
}
✅ ft_strcapitalize — 단어 첫 글자만 대문자로
이 함수는 문자열 안의 "단어"를 인식하고, 첫 글자만 대문자로 바꾸며 나머지는 소문자로 만드는 함수입니다.
단어는 숫자나 문자 외의 문자가 나오면 새로 시작합니다.
char *ft_strcapitalize(char *str)
{
int i = 0;
while (str[i])
{
if (i == 0 || (!(str[i - 1] >= 'a' && str[i - 1] <= 'z') &&
!(str[i - 1] >= 'A' && str[i - 1] <= 'Z') &&
!(str[i - 1] >= '0' && str[i - 1] <= '9')))
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
}
else if (str[i] >= 'A' && str[i] <= 'Z')
str[i] += 32;
i++;
}
return (str);
}
✅ ft_strlcpy — 안전한 문자열 복사
strcpy보다 더 안전한 문자열 복사 함수입니다.
최대 size - 1까지 복사하고 마지막에 \0을 명확히 넣어주며, src의 길이를 반환합니다.
unsigned int ft_strlcpy(char *dest, char *src, unsigned int size)
{
unsigned int i = 0;
unsigned int src_len = 0;
while (src[src_len])
src_len++;
if (size == 0)
return (src_len);
while (src[i] && i < size - 1)
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (src_len);
}
✅ ft_putstr_non_printable — 출력 불가능한 문자들을 \xx 형식으로 출력
문자열 안에 출력 불가능한 문자가 있으면, \ 다음에 16진수로 변환해서 출력합니다.
예: \n은 \0a로 출력됨.
void ft_putstr_non_printable(char *str)
{
char hex_digits[17] = "0123456789abcdef";
char hex[3];
int i = 0;
while (str[i])
{
if (str[i] >= 32 && str[i] <= 126)
write(1, &str[i], 1);
else
{
hex[0] = '\\';
hex[1] = hex_digits[(unsigned char)str[i] / 16];
hex[2] = hex_digits[(unsigned char)str[i] % 16];
write(1, hex, 3);
}
i++;
}
}
✅ ft_print_memory — 메모리 주소, 16진수, 출력 문자까지 한 줄로 보여주는 디버그 출력
이 함수는 메모리의 내용을 주소, hex, char로 출력하는 매우 실용적인 디버깅 도구입니다.
줄마다 16바이트씩 출력하며, 빈 공간도 고려해서 정렬합니다.
코드가 길어 여기선 생략하지만, 핵심 구성은 다음과 같습니다:
- 주소 출력
- 메모리 내용을 16진수로 출력
- 문자 표현으로 오른쪽에 보여줌 (출력 불가능한 문자는 . 처리)
#include <unistd.h>
#define LINE_SIZE 16
void ft_putstr(char *str)
{
while (*str)
write(1, str++, 1);
}
void ft_mem_addr(unsigned long num)
{
char buffer[16];
char *hex_digits;
int i;
hex_digits = "0123456789abcdef";
i = 0;
while (num > 0 || i < LINE_SIZE)
{
buffer[i] = hex_digits[num % 16];
num /= 16;
i++;
}
while (i < 16)
{
buffer[i] = '0';
i++;
}
while (i > 0)
write(1, &buffer[--i], 1);
}
void ft_mem_bytes(unsigned char *mem, unsigned int remain)
{
unsigned int i;
char *hex_digits;
hex_digits = "0123456789abcdef";
i = 0;
while (i < LINE_SIZE)
{
if (i < remain)
{
write(1, &hex_digits[mem[i] / 16], 1);
write(1, &hex_digits[mem[i] % 16], 1);
}
else
write(1, " ", 2);
if (i % 2)
write(1, " ", 1);
i++;
}
}
void ft_mem_chars(unsigned char *mem, unsigned int remain)
{
unsigned int i;
char c;
i = 0;
while (i < LINE_SIZE)
{
if (i < remain)
{
if (mem[i] >= 32 && mem[i] <= 126)
c = mem[i];
else
c = '.';
write(1, &c, 1);
}
else
write(1, " ", 1);
i++;
}
}
void *ft_print_memory(void *addr, unsigned int size)
{
unsigned int i;
unsigned char *mem_blk;
unsigned int remain_size;
mem_blk = (unsigned char *)addr;
i = 0;
while (i < size)
{
remain_size = size - i;
if (remain_size > LINE_SIZE)
remain_size = LINE_SIZE;
ft_mem_addr((unsigned long)&mem_blk[i]);
ft_putstr(": ");
ft_mem_bytes(&mem_blk[i], remain_size);
write(1, " ", 1);
ft_mem_chars(&mem_blk[i], remain_size);
write(1, "\n", 1);
i += LINE_SIZE;
}
return (addr);
}
마무리
c02 과제는 단순한 문자열 함수처럼 보이지만,
실제로는 배열과 포인터의 관계, ASCII 처리, 문자열 종료 조건, 주소와 메모리 조작 등
C언어에서 꼭 알아야 할 핵심들을 담고 있습니다.
하나하나 직접 main 함수로 테스트하면서
"어떤 입력에서 어떻게 동작하는지" 출력 결과를 눈으로 확인해보면
정말 많이 배울 수 있는 과제입니다.
이제 곧 c03로 넘어가겠죠? 그 전에 이 과제만큼은 꼭 완전히 내 것으로 만들고 넘어가시길 바랍니다.
모두 화이팅입니다! 💪

https://github.com/maxkim77/42assignments
GitHub - maxkim77/42assignments
Contribute to maxkim77/42assignments development by creating an account on GitHub.
github.com
'BackEnd > C' 카테고리의 다른 글
[42경산 라피신 과제 뽀개기] C05 과제 수학적 사고와 재귀 로직 훈련하기 (0) | 2025.07.25 |
---|---|
[42경산 라피신 과제 뽀개기] C04과제 기본 입출력과 진법 변환 함수들 (1) | 2025.07.24 |
[42경산 라피신 과제 뽀개기] C03과제 - 문자열 비교, 연결, 검색 함수 총정리 (2) | 2025.07.23 |
[42경산 라피신 과제 뽀개기] C01 과제 기본기 잡는 출력 함수 완전 정리 (1) | 2025.07.14 |
[42경산 라피신 과제 뽀개기] C00 과제 기본기 잡는 출력 함수 완전 정리 (0) | 2025.07.13 |