이 Step에서 다루는 것

  • C 스타일 문자열(C-string)이 왜 char 배열이고, 왜 '\0'가 필수인지
  • const char*(문자열 리터럴)과 char[](수정 가능한 버퍼)의 차이
  • const 위치에 따른 의미를 정확히 읽는 법
  • strlen/strcpy/strcat의 동작과 가장 흔한 버그(버퍼 오버플로우)

학습 목표

  • C 문자열을 한 문장으로 정의할 수 있다. ( “'\0'로 끝나는 char 배열” )
  • “문자열 리터럴은 수정하면 안 된다(UB)”를 이유까지 포함해 설명할 수 있다.
  • const char* / char* const / const char* const를 구분할 수 있다.

C 스타일 문자열

  • C 스타일 문자열(C-string)은 '\0'(널 종료 문자)로 끝나는 char 배열입니다.
  • '\0'가 없으면 strlen, strcpy 같은 함수는 “어디까지가 문자열인지”를 모르고 메모리를 계속 읽다가 사고가 납니다.

예시:

char str1[] = {'H','e','l','l','o','\0'};
char str2[] = "Hello";  // 컴파일러가 자동으로 '\0'을 붙여줌

핵심 체크:

  • "Hello"의 실제 길이(문자 수)는 5지만, 버퍼에는 '\0'까지 포함되어 6칸이 필요합니다.

포인터 vs 배열 (문자열)

선언저장 위치수정
const char* ptr = "Hello"문자열 리터럴은 보통 읽기 전용 메모리(.rdata 등). ptr은 그 주소를 가리킴수정 금지(수정 시 UB)
char str[] = "Hello"수정 가능한 버퍼(지역이면 보통 스택)에 복사본 생성수정 가능
  • 문자열 리터럴은 수정하면 안 됩니다(UB). 그래서 const char*로 받는 게 기본입니다.
const char* p = "Hello";
// p[0] = 'h';  // ❌ UB (절대 하지 말 것)

char s[] = "Hello";
s[0] = 'h';      // ✅ OK (복사본 수정)

const 위치에 따른 의미

const char* a;   // 가리키는 내용 수정 불가, 주소 변경 가능
char* const a;   // 주소 변경 불가, 가리키는 내용은 수정 가능
const char* const a;  // 주소·내용 모두 불변

const를 읽는 안전한 규칙(암기):

  • const바로 옆의 대상을 상수화합니다.
    • 왼쪽에 대상이 있으면 보통 왼쪽
    • 왼쪽에 대상이 없으면 오른쪽을 상수화한다고 생각하면 됩니다.

예:

  • const char* a = “char는 const(내용 불변), 포인터는 가변”
  • char* const a = “포인터는 const(주소 불변), 내용은 가변”

strlen, strcpy, strcat

  • strlen(str): '\0' 전까지의 문자 수(글자 수)를 셉니다.
  • strcpy(dest, src): srcdest로 복사합니다. '\0'까지 포함해서 복사합니다.
  • strcat(dest, src): dest 끝에 src를 이어붙입니다. 역시 dest버퍼 크기가 충분해야 합니다.

가장 중요한 위험:

  • strcpy/strcat은 기본적으로 “버퍼 크기”를 모르기 때문에, 크기 검증 없이 쓰면 버퍼 오버플로우로 이어질 수 있습니다.

체크 질문 (스스로 답해보기)

  • C 문자열에서 '\0'는 왜 반드시 필요할까?
  • const char* p = "Hello";에서 p[0]을 바꾸면 왜 위험할까?
  • strlen("Hello")는 5일까 6일까? 그 이유는?

profile
李家네_공부방

0개의 댓글