C++ 제어 구조의 심화 이해와 효율적인 메모리 활용 기법

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";

태그: cpp reference Union SwitchStatement StringClass

7월 2일 21:50에 게시됨