본문 바로가기

C++ 일기

8. switch문

#include<iostream>

int main()
{
   int num;
   std::cin >> num;
   
   switch(num)
   {
      case 1:
      	std::cout << "1을 입력했습니다.";
      	break;
      case 2:
      	std::cout << "2를 입력했습니다.";
      	break;
      default:
       	std::cout << "입력한 값이 1과 2가 아닙니다.";
       	break;	
   }
   // break;를 만나면 이곳부터 코드가 진행된다
}

위의 식은 switch문의 예시이다.

switch문은 if문과 같은 조건문이지만 조건이 상수인 분기문이다.

switch 안의 소괄호에는 상수에 부합하는 변수를 대입하여 해당 변수와 상수가 같은지를 검사하고,

case 뒤에는 상수를 대입할 수 있다.

종합하자면, switch (num)은 지금부터 조건을 따지려는 변수는 num변수이다. 라고 선언하는 것이고,

case 1: 의 의미는 num변수가 1일 때. 아래의 코드를 실행하겠다 라는 뜻이다.

 

switch문은 상술했듯 조건을 상수로만 설정할 수 있기 때문에, if문 처럼 조건을 논리연산자나 비교연산자로 설정할 수 없다.

따라서 상세한 조건을 설정할 수는 없지만,  변수의 조건이 상수로 떨어지거나, 추후에 다룰 열거형 타입, 'enum'을 분기로 나눌 때의 가독성이 높다.

 

 

break는 실행시 위의 코드에 표시해둔 것 처럼 switch 구문을 즉시 벗어난다. 

이 말은 곧, break를 만나지 않는다면 자동으로 아래의 case를 실행하게 된다는 것이다.

Switch문은 겉으로 보기에 if문 처럼 위에서 아래로 순서대로 case의 결과 값을 일일히 검사하는 것 처럼 보이지만,

실제로는 switch() 부분에서 안의 변수의 값을 검사해서 어느 case 로 이동할지 정한 다음,

해당하는 case로 바로 이동하여 그 case 안의 코드를 실행한 후, break로 빠져나오는 형식이다.

 

이해하기 쉽게 위의 코드와 연계하여 설명하자면,

(전제 : std::cin >> num; 을 통해 입력받은 값은 1이다.)

1. switch(num) 을 통해 num의 값이 무엇인지를 토대로 어느 case로 움직일 것인지 검사한다.

2. num의 값이 1이기 때문에, switch(num)은 코드를 case 1: 이 있는 곳으로 이동시킨다.

3. case 1: 의 코드내용을 진행한다.

4. 코드 진행중 break; 를 만난다.

5. switch 문을 빠져나온다.

의 순서로 진행된다.

 

즉, case 1: 의 역할은 num 변수가 1인지 아닌지를 검사하는 검문소가 아니라,

switch를 통해 검문을 마친 num이 switch의 지시대로 안내 받는 1번 방이라는 것이다.

 

이전에 사용했던 if문은 if와 else if가 각각의 검문소 역할을 담당하였기 때문에 

else로 구분지어져 있는 한, 서로의 영역을 침범할 일이 없었지만,

switch 구문에서는 각 case들이 검문의 역할을 하지 않기 때문에

break로 빠져나오지 않는다면, 위에서부터 아래 순서대로 읽는 코드의 특성 때문에

아래로 흘러내려, 다음 case의 구문까지 읽어버린다는 것이다.

(case 2: 에게는 num변수가 2인지 아닌지 검사하는 기능이 없다.)

 

 

 

 

 

 

이러한 특성 때문에 아래와 같은 현상이 발생하기도 한다.

#include<iostream>

int main()
{
   int num = 3;
   
   switch(num)
   {
      case 1:
      	std::cout << "1";
      case 2:
      	std::cout << "2";
      case 3:
      	std::cout << "3";
      case 4:
      	std::cout << "4";
      case 5:
      	std::cout << "5";
      default:
        std::cout << "디폴트";
         break;
   }
   
   // 출력값 : 345디폴트
}

위 코드의 출력값이 345디폴트 가 되는 이유는,

앞에서 말했듯 break; 를 만나기 전에는 코드가 계속 아래로 진행되는 점 때문이다.

switch를 통해 case 3으로 이동한 코드는 case 3:에서 "3"을 출력한 다음에도 break;를 만나지 못했기 때문에

case 4: , case 5: , default: 를 모두 지나가 지나가는 길에 있는 모든 코드를 실행시켰다.

 

 

 

#include<iostream>

int main()
{
   int num = 3;
   
   std::cout << "3보다 큰 수는 ";
   switch(num)
   {
      case 1:
      	std::cout << "2, ";
      case 2:
      	std::cout << "3, ";
      case 3:
      	std::cout << "4, ";
      case 4:
      	std::cout << "5, ";
      case 5:
      	std::cout << "6, ";
        
        // ...
      default:
        std::cout << "입니다.";
         break;
   }
   // 출력값 : "3보다 큰 수는 4, 5, 6, 입니다.
}

이와 같은 특징을 이용해, 위와 같이 응용할 수 있지만, 이런식으로 사용하는 경우에 최악의 경우 메모리 침범이 일어나

추후 디버깅을 진행함에 있어 어려움을 겪을 수 있으므로 가능한한 break;를 사용하는 것이 중요하다.

 

 

 

 

 

그러면 default:는 무엇일까?

우리는 앞서 switch문의 핵심 동작 방식을 이해했기 때문에 default의 역할을 유추해볼 수 있다.

default는, switch문에서, 소괄호 안의 변수에 부합하는 case가 없을 경우 실행되는 부분이다.

#include<iostream>

int main()
{
   int num;
   std::cin >> num;
   
   switch(num)
   {
      case 1:
      	std::cout << "1을 입력했습니다.";
      	break;
      case 2:
      	std::cout << "2를 입력했습니다.";
      	break;
      default:
       	std::cout << "입력한 값이 1과 2가 아닙니다.";
       	break;	
   }
   // break;를 만나면 이곳부터 코드가 진행된다
}

맨 위의 코드를 다시 가져왔다. 

위의 코드에서 입력값이 1과 2가 아닌, 예를 들어 3을 입력했다고 가정해보자.

switch문에서 준비한 case는 case 1과 case 2뿐이다.

switch는 코드를 case 1로도, case 2로도 데려다줄 수 없기 때문에, 결국 default로 이동시킨다.

쉽게말해 default는, switch가 준비하지 못한 case들에 해당하는 변수를 위한 대피소이다.

 

 

 

또한, 아래와 같이 if문과 마찬가지로 switch문 역시 switch문 안에 switch문, if문을 삽입하는 것이 가능하다.

#include<iostream>

int main()
{
   int jobSelect;
   int skillSelect;

   std::cout << "직업을 선택해라.(1: 전사, 2. 마법사, 3. 레인저) : ";
   std::cin >> jobSelect;
   switch (jobSelect)	// 직업을 선택
   {
	case 1:
	std::cout << "전사 선택. 어떤 공격을 하시겠습니까? (1. 강타, 2.내려찍기) : ";
    
	std::cin >> skillSelect;// 스킬을 선택 (직업을 선택한 다음)
	switch (skillSelect)	
	{
		case 1:
			std::cout << "전사의 강타공격";
			break;
		case 2:
			std::cout << "전사의 내려찍기 공격";
			break;
		default:
			break;
     }
   }
}

 

 

 

 

switch를 다시 공부하면서, switch구문의 매력도 다시 느꼈다.

다시 공부하기 전의 swtich문은, 내게는 else if의 응용판이었다.

if문의 가독성을 올리기위한 도구이자, 열거형 타입 enum의 가독성을 올리는 구문이라고만 생각했는데,

다시 공부해보니 if문과 switch문은 서로 구동방식조차 완전히 다른 구문이었던 것이다.

친척인줄 알았던 if와 switch가 알고보니 친한 친구였을 뿐 이라는 것이다!

덕분에 switch문에 대해 더 자세히 알고싶어졌고, 공부해본 결과 더 깊은 이해가 생긴 것 같다.

'C++ 일기' 카테고리의 다른 글

9 - 2. 반복문 for  (0) 2024.02.23
9 - 1. 반복문 while  (0) 2024.02.23
7. 조건문 if  (0) 2024.02.21
6 - 6. 삼항연산자  (0) 2024.02.20
6 - 4. 비교연산자 ( <, >, <=, >=, !=, ==)  (0) 2024.02.20