왜 C스타일 문자열이 까다로운가?
비교 함정
char name[] = "Rookiss";
char name2[] = "Rookiss";
if (name == name2) { }
- 배열/포인터 문맥에서는 문자열 내용이 아니라 주소가 비교됩니다.
- 내용 비교는
strcmp(name, name2) == 0 같은 함수를 써야 합니다.
null-terminator와 버퍼 관리 부담
- C 문자열은
'\0' 종단 문자를 직접 관리해야 합니다.
strcpy, strcat 사용 시 버퍼 길이 계산 실수로 오버플로우가 발생하기 쉽습니다.
- 안전한 코드 작성을 위해 길이 계산/복사 규칙을 항상 신경 써야 합니다.
std::string의 핵심
본질
std::string은 문자 배열을 안전하게 감싸는 클래스입니다.
- 메모리/길이 관리를 내부에서 수행해 사용성이 훨씬 좋습니다.
- 비교(
==, !=, <)와 결합(+)이 직관적입니다.
std::string a = "Rookiss";
std::string b = "Rookiss";
if (a == b) {
}
자주 쓰는 API
| 메서드 | 설명 |
|---|
size(), length() | 길이(문자열 바이트 수) |
empty() | 비어 있는지 확인 |
append(), += | 뒤에 덧붙이기 |
substr(pos, len) | 부분 문자열 |
find() | 부분 문자열 검색 (npos면 못 찾음) |
replace() | 구간 치환 |
c_str() | C API용 const char* 포인터 |
find + npos 패턴 (필수)
std::string text = "Hello Rookiss";
size_t pos = text.find("Rook");
if (pos != std::string::npos) {
}
npos는 "못 찾음"을 의미하는 특수 값입니다.
find 결과를 바로 인덱스로 쓰기 전에 반드시 npos를 확인해야 합니다.
c_str() 사용 시 수명 주의
std::string s = "abc";
const char* p = s.c_str();
s += "def";
c_str() 포인터는 문자열 내용이 변경되면 무효화될 수 있습니다.
- C API에 넘길 때는 "호출 시점에만" 사용하는 습관이 안전합니다.
UTF-8 환경에서 길이 해석 주의
std::string::size()는 문자 개수가 아니라 바이트 수입니다.
- UTF-8에서 한글/이모지는 여러 바이트를 차지할 수 있습니다.
std::string s = u8"가";
- 이 내용은 다음 Part 9(인코딩)와 바로 연결됩니다.
실전 활용 예
- 로그인: ID/PW 문자열 비교, 접두/접미 검사
- 채팅 필터:
find + replace로 금칙어 마스킹
- 소프트 삭제:
"Player_Deleted" 같은 상태 문자열/닉네임 규칙 적용
std::string nickname = "Rookiss";
if (nickname.find("Admin") != std::string::npos) {
}
자주 하는 실수 + 체크 질문
자주 하는 실수
| 실수 | 문제 |
|---|
find() 결과를 int로 받음 | npos 처리 실수/형 변환 문제 |
c_str() 포인터를 오래 보관 | 원본 문자열 변경 후 댕글링 위험 |
UTF-8 문자열에서 size()를 글자 수로 오해 | UI 잘림/길이 제한 버그 |
| C 문자열 습관대로 수동 버퍼 조작 | 오버플로우/가독성 저하 |
체크 질문 (스스로 답해보기)
std::string::npos는 언제 사용하며 왜 필요한가?
c_str() 포인터가 무효화되는 상황을 설명할 수 있는가?
- UTF-8에서
size()와 "글자 수"가 왜 다를 수 있는가?