티스토리 뷰

내일배움캠프 Unreal_7기

TIL - 13일차

tkdqls 2025. 12. 15. 21:17

🟩 오늘의 목표

  • C언어의 char*를 이용해 문자열의 끝(Null Terminator)과 메모리 구조를 이해한다.
  • std::string 없이 포인터 연산만으로 문자열 길이와 특정 문자를 찾아내는 원리를 파악한다.
  • Low-level(C)의 동작 원리를 바탕으로 High-level(C++)의 편리함을 이해한다.

 

🟧 포인터와 문자열 (Memory View)


🟦 문자열의 메모리 구조

  • Null Terminator (\0): C/C++에서 문자열의 끝은 항상 0(Null)으로 표시된다. 컴퓨터는 이 값을 만날 때까지 메모리를 계속 읽는다.
  • 배열과 포인터: 배열의 이름(str)은 메모리의 첫 번째 주소를 가리킨다.
    • 함수로 전달될 때 char str[]은 char *str로 변환(Decay)된다.

🟦 포인터 연산 (Pointer Arithmetic)

  • ptr++의 의미: 단순히 숫자 1을 더하는 것이 아니라, sizeof(타입)만큼 메모리 주소를 이동시킨다.
    • char*는 1바이트씩, int*는 4바이트씩 이동한다.
  • *ptr vs ptr:
    • ptr: 메모리의 주소 (어디에 있는가?)
    • *ptr: 그 주소에 들어있는 (무엇이 있는가?)

 

🟧 오늘 풀어본 문제 정리


🟦 문제 1: 포인터로 문자열 길이 직접 구하기 (my_strlen)

  • 라이브러리 함수 없이 포인터 이동만으로 길이를 계산한다.
C
#include <stdio.h>

int my_strlen(const char *s)
{
    int len = 0;
    // 포인터가 가리키는 값이 '\0'(문자열 끝)이 아닐 때까지 반복
    while (*s != '\0')
    {
        len++;
        s++;       // 포인터 주소 1칸 이동 (char 크기만큼)
    }
    return len;
}

int main(void)
{
    char str[100];
    printf("문자열 입력: ");
    scanf("%s", str); // 공백 전까지만 입력받음

    printf("문자열 길이: %d\n", my_strlen(str));
    return 0;
}

C++에서는 std::string 클래스를 사용하여 메모리 관리 없이 편하게 사용한다.

std::string s = "Hello";
cout << s.length(); // 내부적으로는 위와 같은 원리로 길이를 관리함

🟦 문제 2: 특정 문자 개수 세기 (count_char)

  • 포인터가 가리키는 **주소(s)**와 그 주소에 있는 **값(*s)**을 명확히 구분하여 사용한다.
C
#include <stdio.h>

int count_char(const char *s, char ch)
{
    int count = 0;
    while (*s != '\0')
    {
        // *s (값)이 찾는 문자(ch)와 같은지 비교
        if (*s == ch)
            count++;
        s++; // 다음 주소로 이동
    }
    return count;
}

int main(void)
{
    char str[100];
    char ch;

    scanf("%s", str);
    // %c 앞에 공백을 넣어 이전 입력의 엔터(개행)를 무시
    scanf(" %c", &ch); 

    printf("'%c' 개수: %d\n", ch, count_char(str, ch));
    return 0;
}

C++에서는 <algorithm> 헤더의 std::count 함수를 사용하거나 string의 기능을 활용한다.

#include <algorithm>
std::string s = "Hello";
int count = std::count(s.begin(), s.end(), 'l'); // 이터레이터 활용

 

🟫 오늘 느낀 점

  • 편하게 쓰던 std::string도 결국 포인터 연산이 기반임을 깨닫고, 원리 이해의 중요성을 확실히 느꼈다. 특히 *s(값)와 s(주소)를 구분하여 사용하는 연습이 많이 되었다.