CPP 기초 불리언 및 문자와 문자열
불리언 (bool)
bool isAlive = true;
bool isDead = false;
cout << isAlive; // 1 출력
cout << isDead; // 0 출력
실체는 1바이트 정수. 어셈블리에는 boolean이 없다. 0이면 false, 나머지는 true.
단순히 1과 0의 표현보다 가독성이 매우 뛰어나므로 사용함.if (hp > 0)
보다 if (isAlive)
가 의도가 명확함.
부동소수점 (Floating Point)
기본 타입
float f = 3.14f; // 4바이트, f 붙여야 float
double d = 3.14; // 8바이트, 기본값
f를 붙이는 이유는? 리터럴 3.14는 기본적으로 double. float에 넣으면 암시적 변환 발생.
IEEE 754 표준
float (32비트): [부호 1비트][지수 8비트][가수 23비트]
double (64비트): [부호 1비트][지수 11비트][가수 52비트]
floating point = 떠다니는 소수점 (안움직이는 부동아님 뜰 부임)
// 3.141592를 다음과 같이 저장:
// 0.3141592 × 10¹ (소수점 위치가 "떠다님")
// 314.1592 × 10⁻² (같은 값, 다른 표현)
정밀도 한계
float f = 0.1f + 0.2f;
cout << (f == 0.3f); // false! (부동소수점 오차)
// 해결책: 오차 범위 내에서 비교
float epsilon = 0.00001f;
bool equal = abs(f - 0.3f) < epsilon;
문자 (char)
char ch = 'a'; // 작은따옴표
char ch2 = 97; // ASCII 코드로 직접 대입 (결과는 같음)
char ch3 = 'a' + 1; // 'b' (ASCII 연산)
char 타입은 1바이트 정수. ASCII 코드로 문자를 숫자로 매핑.
유니코드와 wchar_t
wchar_t wch = L'한'; // L 접두사, 2바이트
// 출력 방법
wcout.imbue(locale("kor"));
wcout << wch << endl;
인코딩 방식:
- UTF-8: 영문 1바이트, 한글 3바이트 (웹 표준)
- UTF-16: 대부분 문자 2바이트 (윈도우 내부), 아주 일부만 4바이트
Escape Sequence
char tab = '\t'; // 탭
char newline = '\n'; // 개행
char quote = '\''; // 작은따옴표
char backslash = '\\'; // 백슬래시
새 프로젝트를 열면 있는 Hello World에도 \n 이 포함되어 있다.
문자열 (String)
C 스타일 문자열
char str[] = {'h', 'e', 'l', 'l', 'o', '\0'}; // 수동 null terminator
char str2[] = "hello"; // 자동 null terminator
cout << str2; // hello 출력
중요: \0
(null terminator)가 문자열의 끝을 알려줌. 없으면 쓰레기값까지 출력.
C++ string 클래스 (권장)
#include <string>
string name = "Huxlley";
string greeting = "Hello, " + name + "!";
cout << greeting.length(); // 문자열 길이
cout << greeting[0]; // 첫 번째 문자
C 스타일 vs C++ string:
// C 스타일 (메모리를 직접 할당해줘야하는 번거로움, 아래의 경우에도 95바이트 가량 낭비임)
char str1[100] = "Hello";
char str2[100] = "World";
strcat(str1, str2); // 문자열 연결
// C++ 스타일 (자동으로 메모리를 관리해줌. 아래의 경우엔 5바이트 + 여유분 조금)
string str1 = "Hello";
string str2 = "World";
string result = str1 + str2; // 연결
버퍼 오버플로우 위험
C 스타일: 버퍼 오버플로우 위험
char str1[10] = "Hello";
char str2[20] = "World!!!!!!!!!!";
strcat(str1, str2); // 크래시! str1 크기 초과
// str1은 10바이트인데 결과는 20바이트 필요
실제 메모리 상황:
str1 메모리: [H][e][l][l][o][\0][?][?][?][?]
0 1 2 3 4 5 6 7 8 9
strcat 후: [H][e][l][l][o][W][o][r][l][d][!][!][!][!][!][!][\0]
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
↑ 범위 초과! 다른 변수 메모리 침범
C++ string: 자동 확장
string str1 = "Hello";
string str2 = "World!!!!!!!!!!";
string result = str1 + str2; // 안전! 필요한 만큼 자동 할당
실제로 쓸때
문자열 비교:
// C 스타일 (잘못된 방법)
char str1[] = "hello";
char str2[] = "hello";
if (str1 == str2) // 주소 비교! 항상 false
// C++ 스타일 (올바른 방법)
string str1 = "hello";
string str2 = "hello";
if (str1 == str2) // 내용 비교, true
성능 고려사항:
// 문자열 연결이 많을 때
string result;
for (int i = 0; i < 1000; ++i) {
result += "hello"; // 매번 메모리 재할당 (느림)
}
// 더 효율적인 방법
result.reserve(5000); // 미리 메모리 할당
다양한 버그
버퍼 오버플로우 보안 취약
char username[20];
cout << "사용자명: ";
cin >> username; // 20자 이상 입력하면 해킹 가능
// 해커가 100글자 입력 → 스택 메모리 오염 → 코드 실행 권한 탈취
메모리 누수
char* str = new char[1000]; // 동적 할당
strcpy(str, "Hello");
// delete[] str; // 깜빡하면 메모리 릭
초기화 실수
char str[100]; // 쓰레기값
strcat(str, "Hello"); // 쓰레기값 + "Hello" = 예측불가