1. do-while 반복문의 구조와 활용
C++에서 do-while문은 조건식을 평가하기 전에 코드 블록을 최소 한 번은 실행해야 할 때 사용하는 제어 구조입니다.
1.1 기본 메커니즘
do {
// 최소 1회 실행되는 로직
} while (반복_조건);
일반적인 while문은 진입 전 조건을 검사하지만, do-while은 본문을 먼저 실행한 후 마지막에 조건을 확인합니다.
1.2 실전 활용 사례
사용자 입력 검증
특정 범위의 값을 입력받을 때까지 반복하는 구조에 적합합니다.
#include <iostream>
int main() {
int user_input;
do {
std::cout << "1에서 10 사이의 숫자를 입력하세요: ";
std::cin >> user_input;
} while (user_input < 1 || user_input > 10);
std::cout << "입력된 값: " << user_input << std::endl;
return 0;
}
명령어 기반 메뉴 시스템
#include <iostream>
int main() {
char command;
do {
std::cout << "\n--- 작업 메뉴 ---" << std::endl;
std::cout << "a: 데이터 추가\ns: 데이터 검색\nq: 종료" << std::endl;
std::cout << "선택: ";
std::cin >> command;
if (command == 'a') std::cout << "데이터를 추가합니다." << std::endl;
else if (command == 's') std::cout << "데이터를 검색합니다." << std::endl;
} while (command != 'q');
return 0;
}
2. switch 문을 이용한 다중 분기 처리
switch문은 하나의 변수 값을 여러 상수와 비교할 때 if-else if보다 가독성과 성능 면에서 유리할 수 있습니다.
2.1 핵심 규칙
- 조건식의 결과는 반드시 정수형(int, char, enum 등)이어야 합니다.
- 각
case는 컴파일 타임 상수여야 합니다. break문이 없으면 다음case로 실행 흐름이 넘어가는 'Fall-through' 현상이 발생합니다.
2.2 의도적인 Fall-through 활용
#include <iostream>
int main() {
int category;
std::cout << "월(1-12)을 입력하세요: ";
std::cin >> category;
switch (category) {
case 3: case 4: case 5:
std::cout << "봄입니다." << std::endl;
break;
case 6: case 7: case 8:
std::cout << "여름입니다." << std::endl;
break;
case 9: case 10: case 11:
std::cout << "가을입니다." << std::endl;
break;
case 12: case 1: case 2:
std::cout << "겨울입니다." << std::endl;
break;
default:
std::cout << "잘못된 입력입니다." << std::endl;
}
return 0;
}
3. string 클래스를 이용한 문자열 제어
C++의 std::string은 메모리 관리와 문자열 조작을 안전하게 처리하는 강력한 기능을 제공합니다.
3.1 주요 메서드 활용
#include <iostream>
#include <string>
int main() {
std::string text = "C++ Programming";
// 정보 추출
size_t len = text.length();
bool is_empty = text.empty();
// 조작
text.append(" is powerful");
std::string sub = text.substr(0, 3); // "C++"
// 탐색 및 치환
size_t pos = text.find("powerful");
if (pos != std::string::npos) {
text.replace(pos, 8, "fast");
}
// 변환
std::string s_num = std::to_string(2024);
int n_val = std::stoi("100");
return 0;
}
4. 참조자(Reference)의 개념과 응용
참조자는 기존 변수에 대한 또 다른 이름(별칭)을 부여하는 것으로, 포인터와 유사하지만 더 안전한 문법을 제공합니다.
4.1 참조자의 특징
- 선언과 동시에 반드시 초기화해야 합니다.
- 한 번 초기화되면 다른 변수를 참조하도록 변경할 수 없습니다.
- 널(Null) 참조를 허용하지 않습니다.
4.2 함수 파라미터에서의 참조 전달
값에 의한 전달(Pass by value)은 객체의 복사본을 생성하여 오버헤드가 발생하지만, 참조 전달(Pass by reference)은 원본 데이터에 직접 접근하므로 효율적입니다.
#include <iostream>
#include <vector>
// 효율적인 읽기 전용 참조 전달
void displayData(const std::vector<int>& vec) {
for (int n : vec) {
std::cout << n << " ";
}
}
// 원본 데이터를 수정하는 참조 전달
void swapValues(int& lhs, int& rhs) {
int temp = lhs;
lhs = rhs;
rhs = temp;
}
int main() {
int x = 100, y = 200;
swapValues(x, y);
// x는 200, y는 100이 됨
return 0;
}
5. 공용체(Union)를 활용한 메모리 절약
공용체는 모든 멤버가 동일한 메모리 주소를 공유하는 특수한 구조체입니다. 여러 멤버 중 한 번에 하나의 데이터만 저장할 때 사용합니다.
5.1 공용체의 메모리 구조
#include <iostream>
union Packet {
int id;
float weight;
char code;
};
int main() {
Packet p;
std::cout << "공용체 크기: " << sizeof(p) << " 바이트" << std::endl;
// 가장 큰 멤버인 int/float의 크기인 4바이트가 할당됨
p.id = 10;
std::cout << "id 저장 후: " << p.id << std::endl;
p.weight = 55.5f; // 기존 id 값은 덮어쓰여짐
std::cout << "weight 저장 후 id 값: " << p.id << " (예상치 못한 값)" << std::endl;
return 0;
}
5.2 익명 공용체와 구조체의 결합
프로토콜 설계나 하드웨어 레지스터 접근 시 유용하게 사용됩니다.
struct SensorData {
int sensor_type;
union { // 익명 공용체
int digital_val;
float analog_val;
};
};
int main() {
SensorData s;
s.sensor_type = 1;
s.digital_val = 1024; // 구조체 멤버처럼 직접 접근 가능
return 0;
}
5.3 현대적 대안: std::variant
C++17부터는 공용체의 메모리 효율성을 유지하면서도 어떤 타입이 저장되어 있는지 추적 가능한 타입 안전 공용체 std::variant를 사용할 수 있습니다.
#include <variant>
#include <string>
std::variant<int, float, std::string> myValue;
myValue = 10;
myValue = "Safe Union";