관리 메뉴

Kim's Programming

C언어 - 제어문! 소스 일부를 통제한다!(2/2) 본문

Programming/C

C언어 - 제어문! 소스 일부를 통제한다!(2/2)

Programmer. 2015. 7. 15. 23:38

지난 포스팅에서 IF문 FOR문을 알아보았고 이번 포스팅에서 나머지를 알아보도록 하겠습니다.

 

3. while문

 

while문은 for문과 같은 반복문이기도 하면서 성격이 조금 다르기도 하고 조건을 사용한다는 점에서는 if문 하고 비슷한 점을 가지기도 합니다. while문은 조건에 따라서 그 조건이 참인 동안에만 반복을 실행하게 되는 조건문입니다. 우선 while문의 구조부터 살펴 보겠습니다.

while(조건){명령;}의 형태를 띄고 있습니다. 전 포스트에서 for문으로 1부터 100까지 더하는 프로그램을 for문이 아닌 while로 짜보도록 하겠습니다. for문에서는 if문을 넣어서 break;를 넣었었지만 while에서는 그렇게 할 필요가 없습니다. 우선 소스부터 보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
 
int main()
{
    int count = 0;
    int number = 1;// for문의 초기값과 동일
    while (number <= 100)//100이 넘으면 루프 깨짐 for문의 조건 역할
    {
        count = count + number;//반복되는 숫자를 더하여 count에 저장
        number = number + 1;  // for문의 증감역할
    }
    printf("1부터 100까지 더하면 %d 입니다.\n", count);
}
cs

 

for문과 if문이 합쳐진 느낌이 들지 않나요? 하지만 for문과는 다르게 초기값이 조건문 조건안에 있지 않습니다. 그리고 if문의 조건(break; 될 조건)은 while의 조건문에 들어가있네요. 위의 1부터 100까지 더하는 소스의 결과는 다음과 같이 나옵니다.

 

 

while문은 무한루프가 만들기 아주 쉬워요. 위의 소스의 경우는 초기값도 있고 증감을 시켜서 조건이 아니라면 루프가 깨지게 되는 아주 좋은 구조를 가지고 있죠. 즉, 무한 루프를 깨뜨릴 준비가 되어 있는 조건문이 형성 되어있는거에요. 우선 while문의 루프 구성을 먼져 다시 알아 볼께요 while문의 조건이 거짓이 될 때 while문의 루프는 깨지게 되어있어요. 그렇다면 무한루프를 만드는 방법은??? 네 맞아요 while문의 조건이 계속 참이게 하면 되요. 참이게 어떻게 하냐구요? 위의 경우에서는 'num = num + 1' 구문을 삭제 해버려도 조건이 항상 참이기만 하겠죠? 또 다른 방법은 while조건에 TRUE를 넣어 주는거에요 bool형인 TRUE를 참을 뜻하며 (사실 while의 조건 괄호 안의 판단도 bool 형으로 판단했을때 false일때 루프가 깨지게 되어있어요.) 항상 참이게 만들어주면 무한루프를 형성할 수 있습니다. 또한 bool형의 true와 같은 말인 숫자 1을 대입해도 무한 루프를 형성 할 수 있습니다.

 

while(true) 명령;

while(1) 명령;

모두 무한 루프를 형성할 수 있습니다.

 

while문의 변형 do while문

 

do while문은 do 다음의 명령을 while의 조건이 만족하는 동안에 반복을 하는 데에 while과 같습니다. 소스를 작성 할 때는 다음과 같이 됩니다. (while과 같은 1부터 100까지 더하는 소스를 짰습니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
 
int main()
{
    int count = 0;
    int number = 1;
    do
    {
        count = count + number;
        number = number + 1;
    } while (number <= 100);
    printf("1부터 100까지 더하면 %d 입니다.\n", count);
}
cs

물론 결과도 위와 같은 결과가 나옵니다.

 

지금까지 for문, while문 do while문들 조건문 3개를 전부 알아봤습니다. 하지만 전부 "반복을 할 수 있는 조건문이다."라고 알고 있는 것 보다는 언제 무엇을 써야 하는지 알아두는 것이 좋습니다.

 

  1. for문 : for문의 특징은 제어변수를 사용한다는 점입니다. 루프를 통제하는 변수를 선언하고 정해진 범위에 따라서 명령을 반복하는 구조를 가지고 있습니다. 이런 구조적 특징 때문에 for문은 반복의 횟수가 정해져 있는 경우가 많습니다. 또 무한 루프로 작성하지 않는 이상 break;문을 이용해서 루프를 중간에 깨뜨리는 경우도 잘 없습니다. 그래서 for문의 경우는 정해진 갯수의 숫자들을 계산한다거나 평균을 구한다거나 하는 경우 등 정해진 횟수를 반복하는 경우에 많이 씁니다. 또한 for문은 for옆에 괄호 안을 봐서 증감과 조건 반복 횟수등을 바로바로 파악할 수 있습니다.

  2. while문 : whiel문은 루프를 하냐, 안하냐의 조건만 가지고 있는 조건문 입니다. while문안에 명령을 넣어서 제어변수를 넣는다면 제어변수를 이용할 수는 있으나 이 자체로는 제어변수를 가지고 있지는 않습니다. for문과는 다르게 반복횟수를 조정할 수 있다는 것이 특징입니다. 이를 이용해서 정해지지 않은 조건이 계속 다르게 변하는 경우에 사용 하기 적절합니다.

  3. do while문 : do while문은 거의 while문과 일치 합니다. 하지만 while문과 다른점이 있습니다. 그는 처음에 루프로 진입전 while문은 조건을 점검을 한 뒤 루프로 진입 시키지만 do while문의 경우는 일단 루프로 진입 시킨후에 조건에 따라 조건을 점검합니다. 그래서 while로 작성시에는 while문이 아예 작동하지 않는 경우가 생기고 do while의 경우는 무조건 1번은 작동하게 됩니다.

하지만 서로간에 조금씩만 보충하면 유사한 점도 많아서 3개가 서로 상호대체를 할 수도 있습니다.

 

4. switch

 

switch문은 한 변수의 값을 판단하여 그 값에 따라서 개별 처리를 할 수 있게 해주는 다중선택문입니다. 예를 들어서 어떤 변수가 1일때는 덧셈을 하고 2일때는 뺄셈을 하는 경우 같이 변수에 따라서 다르게 하고 싶을 때 switch문을 사용 합니다. 우선 switch 문의 구조부터 알아보겠습니다.

 

switch(변수)

case 값1: 명령; break;

case 값2: 명령; break;

default : 명령; break;

 

다음과 형태를 가지고 있습니다. 간단한 계산하는 소스를 통해서 switch문을 이용해보도록 하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
 
void main()
{
    int select = 0;
    int num_1 = 0, num_2 = 0;
    printf("첫 번쨰 숫자 입력 : ");
    scanf("%d"&num_1);
 
    printf("두 번째 숫자 입력 : ");
    scanf("%d"&num_2);
 
    printf("계산할 식을 선택하세요\n"
           "  덧셈 : 1 , 뺄셈 : 2 \n"
           "  곱셈 : 3 , 나눗셈:4 \n");
    scanf("%d"&select);//select 변수 입력
 
    switch (select)//switch 문을 이용 변수 판단
    {
    case 1://select가 1일 때
        printf("두 숫자를 더합니다 값은 %d입니다\n", num_1 + num_2);
        break;
    case 2://select가 2일 때
        printf("두 숫자를 뺍니다 값은 %d입니다\n", num_1 - num_2);
        break;
    case 3://select가 3일 때
        printf("두 숫자를 곱합니다 값은 %d입니다\n", num_1 * num_2);
        break;
    case 4://select가 4일 때
        printf("두 숫자를 나눕니다 값은 %d입니다\n", num_1 / num_2);
        break;
    default://1~4중 어떤 숫자도 아닐때(해당 case 가 없을때)
        printf("올바르지 않은 선택을 하였습니다. 다시 실행해주세요\n");
        break;
    }
 
}
cs

 두 숫자를 입력 받은 뒤에 1,2,3,4,번 선택을 통하여 사칙연산을 구성 하여 보았습니다. 결과를 한번 살펴 보겠습니다.

 

1과 3이라는 숫자를 num_1과 num_2라는 변수에 대입을 시킨뒤 select 변수에 2를 입력하니 그 다음있는 switch문에서 case 2 에 있는 뺄셈을 실행하여 출력하였습니다.

숫자를 입력후에 select변수에 case에 없는 8을 입력하니 default에 있는 명령이 실행되었습니다. 그렇습니다. switch 문은 괄호안의 변수를 판단하여 그 변수의 값을 가지는 것에 따라 case 중 해당하는 값이 있는지 확인하고 있는 경우 그 case안에 있는 명령을 실행합니다. 만약에 case 중에 해당 값이 없으면 default를 실행을 합니다.

 

switch는 일일이 if else 로 묶어서 switch 문으로 묶을 수 있습니다. 하지만 if문으로 작성을 하는것은 너무 길 뿐만아니라 소스 가독성도 너무 떨어지게 됩니다. 그렇기 때문에 깔끔하게 switch문을 이용하여 작성하는 것이 훨씬 더 좋습니다.

 

switch문을 작성할때 주의 점들을 알아보겠습니다.

 

  1. switch문이 보통 평가하는 변수는 정수형입니다. int, short, unsigned 같은 정수형 변수는 모두 평가 할 수 있습니다. 실수형이나 typedef형은 쓸수가 없습니다. 하지만 문자형, 열거형 등은 사용이 가능합니다. 왜냐하면 문자형, 열거형은 정수형과 호환되기 때문입니다.
  2. case 다음에는 정수,상수 하나가 와야합니다. 변수는 올 수가 없으며 범위형은 되지 않습니다. 비교가 필요한 경우는 if문을 사용하여서 비교를 하여야 합니다.
  3. case문은 점프 위치를 지정하는 일종의 레이블이기 때문에 순서에 대한 제약은 없습니다. case의 숫자가 0 1 2 3 4 순서여도 된고 4 1 3 2 순서여도 상관은 없습니다. 끝에 default의 경우는 case 이외의 경우를 처리하는 부분인데 없어도 상관이 없으나 있을 때 논리적인 흐름에 맞습니다.
  4. default는 필요하지 않으면 생략이 가능합니다. 만약 switch문 안에 아무것도 없으면 그냥 통과하게 됩니다.
  5. 조건에 맞는 case를 만나면 그 case의 아래 있는 모든 것들을 전부 실행하거나 아래중 처음 만나는 break;까지 전부 실행을 합니다. 만약 break;를 쓰지 않으면 전부 실행 해버리게 되기도 하지만, 1이거나 2일때 ' OR ' 판단을 구현할 수는 있습니다.

 

4. 그 외의 제어문들

 

 

goto문

 

goto문은 지정된 곧으로 무조건 점프하는 제어문입니다. goto라는 영어 그대로의 뜻에서 볼 수 있듯이 조건없이 제어를 옮겨 버리기 때문에 사실 가장 사용하기 쉬운 제어문입니다. goto문은 뒤에서 앞으로도 되고 앞에서 뒤로 이동하는것이 가능하지만 같은 함수 내에서만 이동할 수 있으며 다른 함수로는 점프가 불가능 합니다. 제어문 goto는 옮길 지점을 레이블로 표시합니다. 레이블은 일종의 명칭이기에 명칭 규칙에만 맞으면 자유롭게 이용할 수 있다고 합니다. goto문은 다음과 같이 할 수 있습니다.

 

point:

………

………

goto point:

 

goto point라는 명령을 내리면 즉시 point 다음부터 이어서 읽기 시작합니다. goto문과 조건문을 조합하면 모든 반복문을 흉내낼 수 있다고는 하는데 너무 노동이긴 하지만 간단한 조합을 통해서 while문을 흉내내어 위에서 했었던 1부터 100까지 더하는 과정을 소스로 표현하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
 
void main()
{
    int num = 1;
    int sum = 0;
 
point:
    sum = sum + num;
    if (num < 100)// while문의 조건과 같음 즉,100이 넘기전까지 계속 point로 가서 반복하라
    {
        num = num + 1;
        goto point;//point 지점으로 즉시 이동
    }
    printf("1부터 100까지의 합 : %d \n", sum);
}
cs

 

위의 값의 결과는 위에 while에서 예시를 들었던 처럼 5050이 나오게 됩니다.

 

goto문 쓰고 났으면 이렇게 생각할 겁니다. 생각보다 간단한데 뭐가 노동이고 왜 다른 조건문이고 반복문인거를 쓰는거지? 이유는 이리저리 움직이다 보면 꼬이기 십상이기 때문입니다. 한 코드에 goto가 5개만 넘어가도 이 코드가 어떻게 지나가고 어떻게 흘러가는지 또 맞지 않은 다른 곳에 옮겨야 하면 goto를 다 풀어야 할 뿐만 아니라, 수학적으로 goto를 사용하지 않고도 while, switch등 모든 구조를 만들수 있다고 합니다.  

 

break문

 

break문은 for문으로 무한 루프를 작성한뒤에 루프 탈출을 위해 한번 사용 했었습니다. break문은 반복문, switch문에서 사용이 되는 것이며 루프를 탈출 하는 용도로 사용합니다. while문에서 조건이 있으면 탈출하듯 조건이 필요한것이 아니라 break라는것이 선언 하는 순간 바로 루프문은 깨지고 그 다음으로 넘어가게 됩니다. 하지만 다중 루프일 경우에는 모든 루프를 꺠뜨리는게 아니라 break를 품고 있는 루프만 풀리게 됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
 
void main()
{
    for(int i=; i<10 ; i++)
    {
        for(int j=0; j=10;j++)
        {
            break;
        }
    }
}
cs

이런 형태를 가기고 있으면 초기식이 int j 인 루프는 꺠지고 초기식이 int i로 이루어진 루프는 정상적으로 루프를 돌기 시작합니다.

 

또는 break와 비슷하게 goto를 이용하면 break는 한나의 루프만 깨뜨릴수 있지만 한번에 전체 다 깨뜨릴 수도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
 
void main()
{
    for(int i=; i<10 ; i++)
    {
        for(int j=0; j=10;j++)
        {
            goto point;
        }
    }
point:
}
cs

이런 형태인 경우가 그런 경우입니다.

 

continue

 

coutinue문은 루프의 나머지 부분을 무시하고 조건 점검부로 점프하여 루프의 다음값을 실행 하도록 하는 명렵어 입니다. 루프를 돌리던 중에 특정 조건에 대해서는 처리를 제외시키고자 할때 이명영을 사용하는 것입니다. 물론, 루프를 돌던 중 루프의 조건을 다시 점검할 뿐이지 루프를 첨부터 다시 시작하는 것은 아닙니다. 제어변수 값은 그대로 유지되고 다음 증감문으로 이동하는 형태입니다. 잘 사용은 되지 않지만 정밀한 제어구조에 사용합니다. 예시문으로 하나 예시를 들어보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
 
void main()
{
    for (int i = 0; i <= 50; i++)
    {
        if (i % == 0)
        {
            continue;
        }
        if (i % == 0)
        {
            printf("%d\n", i);
        }
    }
}
cs

다음과 같은 소스를 실행하게 되면( i%9 라는 것은 나머지를 구함을 뜻합니다 i%9==0이란 뜻은 9의 배수임을 뜻합니다)  

 

for문이 돌면서 3의 배수일때는 printf를 통해서 출력은 하지만 9의 배수일때는 통과를 하게 만들었기 때문에 3의 배수이면서 9의 배수는 아닌 값들을 출력하게 됩니다. continue문을 while이나 do while문에 쓰게 되면 증감식이 없기 때문에 그냥 처음으로 돌아가게 하기 때문에 단순히 루프의 처음으로 돌아가게만 합니다.

 

break는 반복문, switch문 case에서 쓸 수 있지만 countinue는 반복문 내에서만 사용이 가능합니다. 만약 switch문안에 countinue를 넣게 되면(switch문을 for문이 감싸고 있다고 했을 때) switch문을 감싸고 있는 루프의 선두로 가서 countinue의 기능을 나타내게 됩니다. 단독으로 있는 switch문에다가 countinue문을 넣게 되면 에러처리 하게 됩니다. break문은 반복문이나 switch문 안에 있지 않게 된다면 에러 처리하게됩니다. 이상으로 제어문에 관한 포스팅을 마치겠습니다.