본문 바로가기
IT/C and C++

[C] 프로그램의 흐름을 조절하는 제어문(1/3)

by 타이모리 2023. 1. 4.

프로그램을 만들 때, 그저 우리가 짠 코드가 순서대로 작동하는 프로그램을 만들면 재미가 없습니다.

딱히 그런 일은 프로그램이 아니더라도 충분히 할 수 있는 일들이 많으니까요.

이번에는 프로그램의 흐름을 조절해서 더욱 풍부하고 복잡한 프로그램을 만들기 위한 기초 준비를 해보겠습니다.

목차


    제어문이란?

    제어문은 간단하게 이야기해서, 프로그램의 흐름을 조절할 수 있는 구문을 이야기 합니다.

    어떤 상황이 주어지면, 그 상황을 판단해서 다음 실행될 프로그램 코드를 결정하는 등의 작업을 할 수 있습니다.

    기본적으로 프로그램은 인간이 하기 어렵거나, 귀찮은 작업을 하기 위해서 작성됩니다.

    이를 위해서 복잡한 상황에서도 작동할 수 있도록 프로그램의 흐름을 조절해야만 합니다.

     

    제어문은 조건문, 반복문, 분기문으로 나눌 수 있습니다.

    이번에는 조건문을 알아보는 시간을 가지도록 하겠습니다.

    (참고로, 조건문과 반복문, 분기문으로 나눈 것은 필자의 주관입니다. 이것이 꼭 맞다고 할 수 없습니다. 또한, 여러 제어문을 조건문, 반복문, 분기문으로 분류할 때 다르게 분류되는 경우도 많습니다.)

     

     

     

     

    if 문을 사용하는 방법


    if 문은 가장 기본적인 구문 중 하나입니다.

    제어문 중 가장 많이 사용되는 구문으로, 필히 익혀두셔야 할 개념입니다.

    if 문은 다음과 같이 작성됩니다.

    if (조건식) {
    	(코드)
    }

    실제 영어에서 쓰이는 if의 뜻을 생각해보면 쉽게 파악이 가능합니다.

    (영어에서 if 쓸 때, 접속사로 쓴다거나 그런거 말구요....)

    if 뒤에 있는 (조건식)이 참일 때, (코드)를 실행하게 됩니다.

    조건식은 대체로 1(True), 0(False)가 들어가는 편이지만, 0이 아닌 다른 값을 집어넣어도 참으로 취급합니다.

    때에 따라서는 다양한 활용이 가능합니다.

    조건식 안에 자주 들어가는 조건식은 

    a == b*

    a < b (부등식)

    함수()

    가 있습니다. 함수의 경우, 참 거짓을 판별하는 함수가 되겠습니다.

    *=이 아니라 ==인 이유는 혼동을 막기 위해서입니다. =로 하면 a에 b를 대입하라가 됩니다. ==로 해야지 비교가 됩니다.

     

    결과적으로, 코드를 실행하냐 안 하냐를 조절하는 것이 가능합니다.

    if 문만 쓰면 좀 부족한 느낌이 들 수 있습니다. (안든다구요? 그냥 드세요.)

     

    if 문이 실행되지 않을 때 실행할 코드를 지정할 수도 있습니다.

    if else 문은 if 문에서 좀 더 나아간 코드입니다.

    if (조건식) {
    	(참일 때 실행할 코드)
    }
    else {
    	(거짓일 때 실행할 코드)
    }

    else는 말 그대로 if 문에서 조건식이 거짓일 때 동작할 코드를 결정할 수 있습니다.

    이를 이용하면 더욱 풍부한 프로그램을 구성하는 것이 가능해집니다.

    else는 앞에 if문이 있고 바로 뒤에 나와야 동작하니 꼭 둘을 붙여 쓰시기 바랍니다.

     

    또한 위에서는 제어문을 쓰고, 흐름을 결정할 코드들을  { }로 감싸 작성했습니다.

    그러나, 흐름을 결정할 코드가 한 줄의 코드인 경우(;으로 구분) { }를 쓸 필요 없이, 그냥 제어문 뒤에 붙여 주시기만 해도 충분합니다.

    if (조건식)
    	(참일 때 실행할 코드 1줄)

     

    지금까지 배운 내용에서 약간의 응용을 더하면 아래와 같은 코드를 작성할 수 있습니다.

    if (조건식1) {
    	(조건식1이 참일 때의 코드)
    }
    else if (조건식2) {
    	(조건식1이 거짓이고 조건식2이 참일 때의 코드)
    }
    else if (조건식3) {
    	(조건식1, 조건식2이 거짓이고 조건식3이 참일 때의 코드)
    }
    ...

    이미 코드에 그 동작이 다 나와있지만, 어떻게 하면 저게 가능한지 잠시 생각해봅시다.

    다 생각하셨나요? 그리 어렵지 않게 해석할 수 있습니다.

    위의 코드 형식을 사용하면 아래와 같은 프로그램을 구성할 수 있습니다.

    #include <stdio.h>
    
    int main() {
    	int a = 0;
    	scanf("%d", &a);
    	if (a == 0) {
    		printf("0을 입력하셨습니다.");
    	} else if (a == 1) {
    		printf("1을 입력하셨습니다.");
    	} else {
    		printf("와우! 0과 1이 아닌 수를 입력하셨습니다");
    	}
    }

    0 또는 1을 입력하거나 그 외의 수를 입력했을 때 결과가 달라지는 프로그램입니다.

    위의 형식은 정말 자주 나옵니다. 그러나, 단순히 맞는지 아닌지를 비교하는 프로그램을 if else문 몇 개씩을 이어붙여 작성하는 것은 꽤 효율이 떨어집니다. 이를 위해 조금 더 단순한 switch case 문을 알아보도록 하겠습니다.

     

    switch case 문 사용하는 법


    switch case 문은 단순히 어떤 값이 맞는지 아닌지를 비교할 때 매우 효과적인 구문입니다.

    (정확히 말하면 그 외의 상황에서는 쓸모가 없습니다..)

    다음과 같이 구성됩니다.

    switch(비교당할 값) {
    case 비교할 값1 :
    	(코드1)
    	break;
    case 비교할 값2 :
    	(코드2)
    	break;
    case 비교할 값3 :
    	(코드3)
    	break;
    ...
    default :
    	(코드n)
    	break; //이 놈은 없어도 됩니다만, 저는 그냥 습관적으로 추가했습니다.
    }

    case를 사용해서 비교당할 값이 어떤 값을 가지고 있는지를 비교합니다.

    만약 비교할 값과 비교당할 값이 같다면 프로그램의 흐름은 그 case 구문부터 시작하게 되어있습니다.

    break는 반복문이나, 이 switch 문을 종료할 때 사용됩니다.

    위에서 이야기 했다시피, 흐름의 시작을 값이 같은 case문에서 시작하는 것이기 때문입니다.

    예를 들어 비교할 값2와 비교당할 값이 같고, break 구문이 없다면, 코드2 부터 코드n까지 모두 실행되게 될 것입니다.

    (물론 이를 응용한 프로그램도 있습니다.)

    default는 그냥 실행되는 프로그램으로, switch 문이 살아있는 한 무조건 실행됩니다.

    결과적으로, case가 실행되게 되면 break 구문이 작동하여 switch 문이 죽지만, case중 아무 것도 실행되지 않는다면 default 문이 작동하는 방식입니다.

    이를 이용하면 조금 전에 작성했던 0과 1, 그리고 다른 수에 따라 결과를 출력하는 프로그램을 편하게 작성할 수 있습니다.

    (안 편하다고요? 그럼 if문 쓰시면 됩니다만, switch 문도 좋으니 한 번 잡숴보세요.)

    #include <stdio.h>
    
    int main() {
        int a = 0;
        scanf("%d", &a);
        switch(a) {
        case 0:
        	printf("0을 입력하셨습니다");
            break;
        case 1:
        	printf("1을 입력하셨습니다");
            break;
        default :
        	printf("와우! 0과 1이 아닌 수를 입력하셨습니다.");
            break;
        }
    }

    양만 보면 if else 문과 별 다를 바 없어보이지만, 가독성 면에서 훨씬 나아졌습니다.

    단순 같은지 아닌지 비교하는 것에서는 switch 문을 자주 씁니다.

     

    조건문 없애기!


    (이 내용은 꽤 심화적인 내용입니다. 또한, 당장에 개인의 컴퓨터 성능이 매우 좋아진 이상 이를 신경 쓸 필요도 없습니다. 아직 포스팅하지 않은 내용도 꽤 있습니다)

     

    조건문을 없애는 것은 한 번쯤은 시도해봐야 합니다.

    논리적, 프로그래밍적 사고를 잘 쌓을 수 있기 때문입니다.

    특히 if 문을 없애려는 시도는 해봄직 하기 때문에 이번에 이렇게 들고오게 되었습니다.

    바로 코드부터 보시겠습니다.

    #include <stdio.h>
    
    //char *strings[] = {"짝수", "홀수"};
    int main() {
        int a = 0;
        scanf("%d", &a);
        if (a % 2 == 0) printf("짝수");
        else printf("홀수");
    }

    간단하게 입력한 수의 홀/짝 여부를 판별하는 프로그램입니다.

    그러나, if문이 들어가 있습니다. (정상아니냐구요? 정상입니다.)

     

    컴퓨터는 처리할 때, 미리 앞에 실행될 프로그램 코드를 예측해서 작업 성능을 높입니다.

    그러나, if문의 경우 조건식이 참/거짓이냐에 따라 실행되는 것이 달라집니다.

    결과적으로, if문을 많이 쓰면 쓸 수록 프로그램의 성능이 낮아지게 됩니다.

     

    우리가 C언어 상에서만 작업을 하고, 대규모 프로젝트에 참여하지 않는 이상 그리 큰 속도 문제가 일어나지 않기에 if문을 막 써도 됩니다.

    또한 현 시대로 들어와서, 이미 좋아질대로 좋아진 전자기기의 성능에 if문이 그리 큰 영향을 끼치지 못합니다.

    그러나, 아주 미미한 차이여도 존재는 하기에, 이러한 성능 차이가 쌓이고 쌓이다 보면 큰 영향을 끼칠 수도 있습니다.

    (예를 들면 게임같은 경우 말입니다.)

     

    그래서 사람들은 다양한 방법으로 프로그램의 속도를 높이는 방법을 개발했고, 그 중 하나가 if문의 사용 최소화입니다.

    아래의 코드를 봅시다.

    #include <stdio.h>
    
    char *strings[] = {"짝수", "홀수"};
    int main() {
        int a = 0;
        scanf("%d", &a);
        printf("%s", strings[a&1]);
    }

    믿기지 않으실수도 있겠지만, 위의 홀/짝 구분해주는 프로그램과 같은 동작을 실행해줍니다.

    & 라는 bit 연산자는 두 값을 이진수로 변환하고, 각 자리수마다 둘 다 1일 때만 1을 출력합니다.

    따라서, 저 코드의 a&1 은 이진수 상태 a의 첫번째 자릿수가 1일 때 1을 출력하고, 0일 때는 0을 출력합니다.

    또한 이진수에서 첫번째 자릿수가 1일 때는 홀수고 0일 떄는 짝수입니다.

    결과적으로 a&1은

    a가 홀수일 때, 1을 출력하고

    a가 짝수일 때, 0을 출력합니다.

    따라서, 다음과 같이 strings[a&1]의 값이 달라집니다.

    a가 홀수일 때, strings[1] => "홀수"

    a가 짝수일 때, strings[0] => "짝수"

    이렇게 말이지요.

    결과적으로 if문을 쓰지 않고 홀/짝을 구별해내는 프로그램을 작성하였습니다.

    여러분도 if 문을 쓴 프로그램에서 바꿀 수 있는 if 문은 바꿔보는 연습을 해봅시다.

    (참고로, 그렇게 바꿔쓰면 가독성이 확 떨어지니 주석을 붙이던가, 아니면 까먹지 맙시다)

     

    마무리

    오늘은 제어문 중 조건문에 관하여 포스팅 해보았습니다.

    어쩌다보니 양이 꽤 길어진 것 같기도 하고, 아닌 것 같기도 하고..

    다음에는 제어문 중 반복문에 관하여 포스팅 해야겠습니다.

    댓글