[따배씨++]Chapter5. 흐름 제어
카테고리: Cpp
태그: Programming
인프런에 있는 홍정모님의 홍정모의 따라하며 배우는 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;
}
댓글 남기기