[따배씨++]Chapter5. 흐름 제어

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모님의 홍정모의 따라하며 배우는 C++ 강의를 듣고 정리한 내용입니다.
공부하는 식빵맘 님의 블로그를 참고했습니다.


🚆 Switch-Case

switch 문법

int main()
{
	int x;
	cin >> x;

	switch(x)
	{
        int y = 5;

	case 0:
	{
		int y = 5;
		cout << y << endl;
	}

	case 1:
	{
		int y = 5;
		y = y - x;
		cout << y << endl;
	}

	default:
		cout << "Undefined input " << x << endl;
	}
}
  • case 하나도 안 걸리면 default 실행
  • break 없으면 밑에 있는 case 다 실행
    • if문과 다른 점. 의도적으로 빼는 경우도 있음
  • switch와 case 사이에서 변수는 선언만 가능
    • 메모리 할당을 못해서 초기화 불가
  • case 안에서 선언해도 switch와 case 사이에서 선언한 것 처럼 작동 (변수 선언은 switch 전체에서 유지)
    • case 벗어나면 메모리 할당 사라짐
  • 그냥 switch 밖에서 선언하고 초기화하는게 편함


Enum과의 시너지

enum class Colors
{
	BLACK,
	WHITE,
	RED,
	GREEN,
	BLUE,
};

void printColorName(Colors color)
{
	switch (static_cast<int>(color))
	{
	case 0:
	{
		cout << "Black";
		break;
	}
	case 1:
	{
		cout << "White";
		break;
	}
	cout << endl;
	}
}
  • enum 내 멤버들을 index로 접근 가능


🚆 While 문

while (1)
{
    static int count = 0;
    cout << count << endl;  // 0 1 2 3 4 ...
    count++;
}

// unsigned int 사용
unsigned int count = 10;

while (count > 0)
{
    if (count == 0) cout << "zero"; // error : overflow 발생

    count--;
}
  • static 변수를 이용하면 변수 값을 유지시킬 수 있음
  • condition 값을 감소시킬때 unsigned 조심해야 함
  • unsigned가 최적화할 때 필요하기 때문에 안 쓰기는 힘듦


do-while 문

int selection = 0; // must be declared outside do-while loop

do
{
    cout << "1. add" << endl;
    cout << "2. sub" << endl;
    cout << "3. mult" << endl;
    cout << "4. div" << endl;

    cin >> selection;
} while (selection <= 0 || selection >= 5);
  • 무조건 한 번은 실행!
  • condition 값을 do{} 안에 선언하면 error
    • do{} 벗어나면 메모리 사라짐 ➡️ 반드시 밖에서 선언
  • while 뒤에 ; 까먹기 쉬움


🚆 난수 만들기

유사 난수 생성

unsigned int PRNG() // pseudo random number generatoion
{
	static unsigned int seed = 5523;
	seed = 8235729 * seed + 2396403;

	return seed % 32768;
}
  • 컴퓨터는 진짜 난수를 만들지 못하므로 유사난수 생성
  • 원리: 시드넘버를 의도적으로 overflow 시킴
  • 시드넘버를 static으로 선언하면 독립 시행처럼 작동 (현재 시간으로 잡는 것도 좋은 방법)
  • 디버깅할 때는 시드넘버를 고정시켜야 함
  • 주의) 나누는 숫자가 크면 값이 쏠리는 현상이 있다고 함


라이브러리 활용

#include <stdlib>

#include <iostream>
#include <cstdlib> //std::rand(), std::srand()
#include <ctime> //std:: time()

using namespace std;

int getRandomNumber(int min, int max)
{
	static const double fraction = 1.0 / (RAND_MAX + 1.0);

	return min + static_cast<int>((max - min + 1)* (std::rand()*fraction));
}

int main()
{
	std::srand(static_cast<unsigned int>(std::time(0))); // 시드넘버 : 현재 시간

	for (int count = 1; count <= 100; ++count)
	{
		cout << getRandomNumber(5, 8) << "\t";

		if (count % 5 == 0) cout << endl;
	}
	return 0;
}


#include <random>

int main()
{
	std::random_device rd; 

	std::mt19937_64 mersenne(rd()); 
	std::uniform_int_distribution<> dice(1, 6);

	for (int count = 1; count <= 20; ++count)
		cout << dice(mersenne) << endl; 

	return 0;
}
  • 여러 가지 확률 분포 모델을 사용할 수 있음
  • random device 만들고, 생성기 만들고, 어떤 분포 따를지 설정


🚆 std::cin - invalid input handling

사용자의 입력을 처리해야 하는 경우, 프로그래머는 사용자의 입력 오류(의도하던 안 하던)를 항상 고려해야 한다.

대표적인 오류

  • 버퍼에 \n이 남아있는 경우 ➡️ std::cin.ignore(무시할 문자 최대 길이, ‘종료 문자’)
    • std::cin.ignore(32767, '\n') : ‘\n’나올 때까지 32767 길이의 문자 버퍼 비우기
  • 다른 타입의 입력이 들어올 경우 ➡️ std::cin.fail(), std::cin.clear()
    • std::cin.fail() : 입력 오류시 true 리턴, 오류 없으면 false 리턴
    • std::cin.clear() : ‘실패 상태’에 있는 cin 내부 플래그 값을 초기화


예제 코드 (learncpp.com)

#include <iostream>
#include <limits>

void ignoreLine()
{
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

double getDouble()
{
    while (true) // Loop until user enters a valid input
    {
        std::cout << "Enter a double value: ";
        double x{};
        std::cin >> x;

        // Check for failed extraction
        if (std::cin.fail()) // has a previous extraction failed?
        {
            // yep, so let's handle the failure
            std::cin.clear(); // put us back in 'normal' operation mode
            ignoreLine(); // and remove the bad input
            std::cerr << "Oops, that input is invalid.  Please try again.\n";
        }
        else
        {
            ignoreLine(); // remove any extraneous input
            return x;
        }
    }
}

char getOperator()
{
    while (true) // Loop until user enters a valid input
    {
        std::cout << "Enter one of the following: +, -, *, or /: ";
        char operation{};
        std::cin >> operation;
        ignoreLine(); // // remove any extraneous input

        // Check whether the user entered meaningful input
        switch (operation)
        {
        case '+':
        case '-':
        case '*':
        case '/':
            return operation; // return it to the caller
        default: // otherwise tell the user what went wrong
            std::cerr << "Oops, that input is invalid.  Please try again.\n";
        }
    } // and try again
}

void printResult(double x, char operation, double y)
{
    switch (operation)
    {
    case '+':
        std::cout << x << " + " << y << " is " << x + y << '\n';
        break;
    case '-':
        std::cout << x << " - " << y << " is " << x - y << '\n';
        break;
    case '*':
        std::cout << x << " * " << y << " is " << x * y << '\n';
        break;
    case '/':
        std::cout << x << " / " << y << " is " << x / y << '\n';
        break;
    default: // Being robust means handling unexpected parameters as well, even though getOperator() guarantees operation is valid in this particular program
        std::cerr << "Something went wrong: printResult() got an invalid operator.\n";
    }
}

int main()
{
    double x{ getDouble() };
    char operation{ getOperator() };
    double y{ getDouble() };

    printResult(x, operation, y);

    return 0;
}



맨 위로 이동하기

Cpp 카테고리 내 다른 글 보러가기

댓글 남기기