C, 제어문, if, else, switch, goto


이번 챕터의 목표


1. 나이를 입력받고, 버스요금 출력하는 프로그램

c_control_goal1


2. 사칙연산 계산기

c_control_goal2




if, else, else if


제어문 중 하나인 if문입니다.

정말 영어 뜻대로 사용하면 됩니다.

간단한 예제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    int a = 0, b = 0, c = 0, max = 0;
    printf("세 정수를 입력받고, 가장 큰 값 출력하기\n\n");
    
    printf("첫번째 수 입력: ");
    scanf("%d", &a);
    printf("두번째 수 입력: ");
    scanf("%d", &b);
    printf("세번째 수 입력: ");
    scanf("%d", &c);
    
    max = a;
    if(max < b)
    {
        max = b;
    }
    
    if(max < c) max = c;
    
    printf("\nMAX: %d\n\n", max);
    
    return 0;
}

/*
 세 정수를 입력받고, 가장 큰 값 출력하기
 
 첫번째 수 입력: 10
 두번째 수 입력: 20
 세번째 수 입력: -10
 
 MAX: 20
*/

세 정수를 입력받고, 가장 큰 값을 출력하는 프로그램입니다.

먼저 max에 a값을 대입하고 난 후,

if(max < b) 에서 괄호안이 참이라면, max에 b값을 대입합니다.

만약 거짓이라면 max값이 b이상이라는 말이므로 아무일도 일어나면 안되겠죠.

이렇게 if문은 괄호안의 조건식이 참이면 다음 스코프({ })안의 내용을 실행합니다.


그리고 다음줄에 두번째 if문에선 max값과 c값을 비교합니다.

그런데 여기서는 스코프가 쓰이지 않았습니다.

실행할 구문이 한줄이면 이렇게 같은 줄에 쓸 수 있습니다.

두 줄 이상이면 무조건 스코프를 써야합니다.


이번엔 else와 if else까지 사용한 코드를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    int score = 0, flag = 1;
    char grade = 'A';
    printf("시험 점수에 따른 절대등급 출력 프로그램\n\n");
    
    printf("점수를 입력하세요(0~100): ");
    scanf("%d", &score);
    
    if(score < 0 || score > 100) flag = 0;
    else if(score >= 90) grade = 'A';
    else if(score >= 80) grade = 'B';
    else if(score >= 70) grade = 'C';
    else if(score >= 60) grade = 'D';
    else grade = 'F';
    
    if(flag) printf("grade = %c\n\n", grade);
    else printf("점수를 잘못 입력 하셨습니다.\n\n");
    
    return 0;
}

/*
 시험 점수에 따른 절대등급 출력 프로그램
 
 점수를 입력하세요(0~100): 85
 grade = B

*/

참고로 flag라는 변수는 점수를 올바르게 입력했는지를

분별하는 변수입니다.

점수를 입력받고 난 후, if문을 차례대로 해석해보겠습니다.

점수가 0미만이거나 100초과면 잘못입력한 것이므로 flag를 0으로 바꿉니다.

그렇지 않고 만약(else if)점수가 90점 이상이면 grade값을 ‘A’로 바꿉니다.

그렇지 않고 만약 점수가 80점 이상이면 grade값을 ‘B’로 바꿉니다.

그렇지 않고 만약 점수가 70점 이상이면 grade값을 ‘C’로 바꿉니다.

그렇지 않고 만약 점수가 60점 이상이면 grade값을 ‘D’로 바꿉니다.

지금까지의 조건도 모두 만족하지 않는다면(else) grade값을 ‘F’로 바꿉니다.


만약 프로그램을 실행시켰을 때, 점수값으로 85를 입력받는다면,

if문에서 이를 처음으로 만족하는 부분은 else if(score >= 80)이고,

grade = ‘B’가 실행된 후, if문을 바로 끝내게 됩니다.


이러한 if문은 중첩해서도 쓸 수 있습니다.

즉, if문안에 또 if문이 들어갈 수 있습니다.

위의 절대등급 출력 프로그램을 3중 if문을 써서 작성해보겠습니다.

#include <stdio.h>

int main(void)
{
    int score = 0, flag = 1;
    char grade = 'A';
    printf("시험 점수에 따른 절대등급 출력 프로그램\n\n");
    
    printf("점수를 입력하세요(0~100): ");
    scanf("%d", &score);
    
    if(score < 0 || score > 100) flag = 0;
    else
    {
        if(score >= 80)
        {
            if(score >= 90) grade = 'A';
            else grade = 'B';
        }
        else
        {
            if(score >= 70) grade = 'C';
            else if(score >= 60) grade = 'D';
            else grade = 'F';
        }
    }
    
    if(flag) printf("grade = %c\n\n", grade);
    else printf("점수를 잘못 입력 하셨습니다.\n\n");
    
    return 0;
}

/*
 시험 점수에 따른 절대등급 출력 프로그램
 
 점수를 입력하세요(0~100): 75
 grade = C

*/

위 코드의 흐름도는 아래 그림과 같습니다.

c_if_else_ex_flow




switch-case 문


switch-case 문의 간단한 예제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    int score = 0;
    char grade = 'A';
    printf("시험 점수에 따른 절대등급 출력 프로그램\n\n");
    
    printf("점수를 입력하세요(0~100): ");
    scanf("%d", &score);
    
    switch(score/10)
    {
        case 10:
            grade = 'A';
            break;
            
        case 9:
            grade = 'A';
            break;
            
        case 8:
            grade = 'B';
            break;
            
        case 7:
            grade = 'C';
            break;
            
        case 6:
            grade = 'D';
            break;
            
        default:
            grade = 'F';
    }
    
    printf("\ngrade: %c\n\n", grade);
    
    return 0;
}

/*
 시험 점수에 따른 절대등급 출력 프로그램
 
 점수를 입력하세요(0~100): 65
 
 grade: D
*/

점수를 입력받고 난 후, switch 구문부터 보겠습니다.

switch(score/10)에서 괄호 안에 있는 score/10이 기준이 됩니다.

각각의 case 뒤에 있는 값이 score/10 을 나타냅니다.

만약 score가 65라 했을 때, switch에서는 score/10을 계산하여

6을 임시 메모리에 저장합니다.

이제 위에서부터 차례대로 case 10일때, case 9일때… 가다가

case 6일때가 조건에 맞으므로 grade = ‘D’가 되고 break를 통해 switch 구문을 빠져나갑니다.

default(기본값)는 모든 경우일 때를 말합니다.

보통은 위에 적은 모든 case에 해당이 안될 때 적용값으로 이용됩니다.


여기서 break를 쓰는게 매우 중요합니다. 예를 들어 안쓴다면…

#include <stdio.h>

int main(void)
{
    int score = 0;
    char grade = 'A';
    printf("시험 점수에 따른 절대등급 출력 프로그램\n\n");
    
    printf("점수를 입력하세요(0~100): ");
    scanf("%d", &score);
    
    switch(score/10)
    {
        case 10:
            printf("case 10\n");
            grade = 'A';
            
        case 9:
            printf("case 9\n");
            grade = 'A';
            
        case 8:
            printf("case 8\n");
            grade = 'B';
            
        case 7:
            printf("case 7\n");
            grade = 'C';
            
        case 6:
            printf("case 6\n");
            grade = 'D';
            
        default:
            printf("default\n");
            grade = 'F';
    }
    
    printf("\ngrade: %c\n\n", grade);
    
    return 0;
}

/*
 시험 점수에 따른 절대등급 출력 프로그램
 
 점수를 입력하세요(0~100): 75
 case 7
 case 6
 default
 
 grade: F
*/

아까전에 코드와 내용은 같은데,

각 case의 실행 여부를 판단하기 위해 printf구문을 넣었고, break를 모두 뺏습니다.

그랬더니 75를 입력하자 case 7만 실행되고 끝나는게 아니라 밑의 코드까지 모두 실행되버립니다.

이게 알맞게 break를 써야하는 이유입니다.


그런데 의도적으로 break를 안쓰는 경우도 있습니다.

예를 들어 이 절대등급 출력 프로그램은

case 10일때나 case 9일때나 등급은 ‘A’로 같습니다.

이럴 때 다음과 같이 코드를 작성할 수 있습니다.

#include <stdio.h>

int main(void)
{
    int score = 0;
    char grade = 'A';
    printf("시험 점수에 따른 절대등급 출력 프로그램\n\n");
    
    printf("점수를 입력하세요(0~100): ");
    scanf("%d", &score);
    
    switch(score/10)
    {
        case 10:
        case 9:
            grade = 'A';
            break;
            
        case 8:
            grade = 'B';
            break;
            
        case 7:
            grade = 'C';
            break;
            
        case 6:
            grade = 'D';
            break;
            
        default:
            grade = 'F';
    }
    
    printf("\ngrade: %c\n\n", grade);
    
    return 0;
}

/*
 시험 점수에 따른 절대등급 출력 프로그램
 
 점수를 입력하세요(0~100): 100
 
 grade: A

*/

case 10 부분에는 break를 적지않아 자연스럽게 case 9가 실행되고,

break를 통해 빠져나가 의도한 값이 출력되는 걸 볼 수 있습니다.




goto 문


goto는 break 처럼 특정 위치로 프로그램의 흐름을 즉시 변경하는 제어문입니다.

다만 break는 자기가 속해있는 스코프 밖으로만 빠져나갈 수 있지만,

goto는 프로그램의 어디로든 이동할 수 있습니다.

간단한 예제입니다.

#include <stdio.h>

int main(void)
{
    int input = 0;
    printf("0~9 사이의 수를 입력 받을때까지 계속 정수를 입력받는 프로그램입니다.\n\n");
    
INPUT:
    printf("정수를 입력하세요: ");
    scanf("%d", &input);
    
    if(input < 0 || input > 9)
    {
        printf("범위 밖의 수를 입력하였습니다. 다시 입력하십시오.\n\n");
        goto INPUT;
    }
    
    puts("Program End");
    
    return 0;
}

/*
 0~9 사이의 수를 입력 받을때까지 계속 정수를 입력받는 프로그램입니다.
 
 정수를 입력하세요: -10
 범위 밖의 수를 입력하였습니다. 다시 입력하십시오.
 
 정수를 입력하세요: 99
 범위 밖의 수를 입력하였습니다. 다시 입력하십시오.
 
 정수를 입력하세요: 7
 Program End
*/

INPUT: 이라는 레이블을 만들어서

범위 밖의 수가 입력됐을 때, goto를 통해 INPUT: 위치로 이동하는 방식입니다.


편한 제어문 같지만, 될 수 있으면 피해야할 구문입니다.

프로그램이 조금만 복잡해져도 심각한 논리오류에 빠질 수 있기 때문입니다.

이때문에 많은 사람들이 goto문을 사악한 코드(evil code)라 부르며

절대 사용하지 말라고 권한다고 합니다.

이런게 있다 라고만 알고 넘어가면 될 것 같습니다.




Back to the Goal


1. 나이를 입력받고, 버스요금 출력하는 프로그램

c_control_goal1

#include <stdio.h>

int main(void)
{
    int age = 0, originalFee = 1000, fee = 1000;
    printf("단계별 분류에 따른 버스요금 계산 프로그램\n");
    printf("정가: 1000원\n");
    printf("0~3세: 100%% 할인\n");
    printf("4~13세: 50%% 할인\n");
    printf("14~19세: 25%% 할인\n");
    printf("65세 이상: 100%% 할인\n\n");
    
    printf("나이를 입력하세요: ");
    scanf("%d", &age);
    
    if (age >= 65) fee = originalFee * 0;
    else if (age >= 20) fee = originalFee;
    else if (age >= 14) fee = originalFee * 0.75;
    else if (age >= 4) fee = originalFee * 0.5;
    else fee = originalFee * 0;
    
    printf("최종요금: %d원\n\n", fee);
    
    return 0;
}


2. 사칙연산 계산기

c_control_goal2

#include <stdio.h>

int main(void)
{
    printf("계산기 프로그램\n");
    printf("입력 예시: 4+3\n\n");
    char calcOperator = 0;
    int x = 0, y = 0, result = 0, flag = 1;
    
    printf("입력: ");
    scanf("%d%c%d", &x, &calcOperator, &y);
    
    switch (calcOperator)
    {
        case '+':
            result = x + y;
            break;
            
        case '-':
            result = x - y;
            break;
            
        case '*':
            result = x * y;
            break;
            
        case '/':
            result = x / y;
            break;
            
        default:
            flag = 0;
            puts("ERROR: 올바르지 않은 연산기호가 입력되었습니다.");
    }
    
    if (flag) printf("Result: %d\n\n", result);
}