본문 바로가기

반복문

1. 반복문

 

문자열  "Hello, world!"  를 5번 출력하려면 어떻게 해야 할까?

당연히  printf("Hello, world!\n"); 를 5번 호출하면 된다.

 

그럼 문자열  "Hello, world!"  를 10번 출력하려면 어떻게 해야 할까?

당연히  printf("Hello, world!\n"); 를 10번 호출하면 된다.

 

문자열  "Hello, world!"  를 500번 출력하려면 어떻게 해야 할까?

그 때도  printf("Hello, world!\n"); 를 500번 호출할 것인가?

 

물론 가능은 하겠지만, (500번을 세야 하니) 코딩 하기도 불편하고, 비효율적이다.

그래서 같은 작업을 여러번 수행하고 싶을 때는 반복문을 사용하는 것이 좋다.

 

C언어에는 while 문, do-while 문, for 문의 세 가지 반복문이 있다.

같은 순서로 알아보자.

 

 

 

2. while 문

 

while 문은 다음의 형식으로 사용한다.

 

while(조건식) 

{

실행문

}

...

 

조건을 만족하는 동안은 내부의 실행문을 실행하고, 

조건이 만족되지 않으면 반복문을 탈출한다.

 

C언어에서 일반적으로 참은 1, 거짓은 0으로 나타낸다는 것을 기억하는가?

그렇다. 조건의 만족 여부는 조건식의 값이 1인지 0인지 확인하는 것이다.

다시 말해, 조건식의 값이 1이면 내부의 실행문을 실행하고,

조건식의 값이 0이면 탈출한다는 것이다.

 

다음은 whlie 문의 예시다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
    int num = 0;
 
    while (num < 3)
    {
        printf("Hello, world!\n");
        ++num;
    }
 
    return 0;
}
cs

 

 

위 코드를 실행한다면  "Hello, world!\n" 는 몇 번 출력될까?

 

num0일 때: num < 3 (조건 만족)          

->  printf("Hello, world\n");

    ++num; //num은 1이 됨

 

num이 1일 때: num < 3 (조건 만족)            

->  printf("Hello, world\n");

    ++num; //num은 2가 됨

 

num이 2일 때: num < 3 (조건 만족)          

->  printf("Hello, world\n");

    ++num; //num은 3이 됨

 

num이 3일 때: num >= 3 (조건 불만족)           

->  return 0;

 

따라서 총 세 번 출력된다.

 

만약에 위 코드의 10행  ++num; 을 주석 처리하면 어떻게 될까?

 

 num 의 값은 계속  0 인 상태에 머무르고,  num < 3 은 계속 참이 된다.

따라서  printf("Hello, world!\n"); 를 영원히 호출하게 된다.

 

이런 경우를 무한 루프(infinite loop)라고 한다.

루프(loop)란 원래 고리라는 뜻의 단어인데, 프로그래밍에서는 반복되는 작업을 말한다.

그러니까 무한 루프라는 것은 어떤 작업이 무한히 반복되는 것을 말하고,

반복문에서 작업이 무한히 반복되면 무한 루프를 돈다고 표현한다.

 

무한 루프의 문제점은 프로그램 실행이 끝나지 않는다는 것이다.

말 그대로 '무한' 루프기 때문에 같은 작업을 강제 종료를 하기 전에는 영원히 반복한다.

이는 비정상적인 종료기 때문에, 바람직한 현상이라고 볼 수 없다.

따라서 다음과 같은 결론을 낼 수 있다.

 

반복문 안에는 반드시 반복 조건을 거짓으로 만들기 위한 연산이 있어야 한다

 

반복문은 프로그래밍에서 자주 쓰이는 요소이므로, 세부적인 실행 순서를 이해할 필요가 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
int main()
{
    int num = 0;
 
    while (num < 3)
    {
        printf("Hello, world!\n");
        ++num;
    }
    return 0;
}
cs

 

앞에서 본 코드다. 이 코드가 실행되는 순서는 다음과 같다.

 

① 7행: num < 3인가? -> num = 0이므로 조건식 num < 3은 참이다. 

          따라서 9행으로 이동한다.

② 9행: "Hello, world!\n"을 출력한다.

③ 10행: num 값을 1 늘린다.

 

④ 7행: num < 3인가? -> num = 1이므로 조건식 num < 3은 참이다. 

          따라서 9행으로 이동한다.

⑤ 9행: "Hello, world!\n"을 출력한다.

⑥ 10행: num 값을 1 늘린다.

 

⑦ 7행: num < 3인가? -> num = 2이므로 조건식 num < 3은 참이다. 

          따라서 9행으로 이동한다.

⑧ 9행: "Hello, world!\n"을 출력한다.

⑨ 10행: num 값을 1 늘린다.

 

⑩ 7행: num < 3인가? -> num = 3이므로 조건식 num < 3은 거짓이다. 

          따라서 반복을 끝내고 12행으로 이동한다.

 

⑪ 12행: 0을 반환하고 프로그램을 종료한다.

 

그러니까 결국 while 문의 실행 흐름은 다음과 같다.

 

조건 검사 → 반복할 코드 실행 → 조건을 거짓으로 만드는 연산 → 조건 검사 → 

 

그리고 조건 검사에서 조건식이 거짓을 반환하면 반복을 멈추는 것이다.

 

 

다음과 같이 정수를 하나 입력받고 그 정수의 구구단을 출력하는 프로그램을 작성해보자.

다소 고전적이지만, 반복문을 처음 접할 때는 구구단만 한 것이 없다.

 

 

 

더보기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
int main()
{
    int num = 1;
    int input;
 
    printf("\n    몇 단?: ");
    scanf("%d"&input);
 
    while (num < 10//num <= 9도 가능
    {
        printf("    %d X %d = %d\n", input, num, input*num);
        ++num;
    }
 
    return 0;
}
cs

 

 

while 문은 다음과 같이 중첩시켜 사용할 수 있다.

 

while(조건식)

{

 

while(조건식)

{
    ...

}

}

 

다음은 중첩 while 문의 예시다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
 
int main()
{
    int a = 0, b = 0;
 
    while (a < 3)
    {
        printf("a: %d\n", a);
 
        b = 0;
        while (b < 4)
        {
            printf("b: %d\n", b);
            ++b;
        }
 
        ++a;
    }
 
    return 0;
}
cs

 

 

 

단순하게 생각하면 쉽다.

조건식을 만족하는 동안 내부 코드를 실행하는 건데, 그 내부 코드가 반복문일 뿐인 것이다.

 

위 코드의 실행 구조는 다음과 같다.

 

 a 가  0 일 때   b 는  0 부터  3 까지 반복한다. 

 a 가  1 일 때   b 는  0 부터  3 까지 반복한다. 

 a 가  2 일 때   b 는  0 부터  3 까지 반복한다. 

 

그러니까  a 는  0 부터  2 까지 반복하는데,

반복할 때마다  b 가  0 부터  3 까지 반복하는 것이다.

 

중첩 반복문을 익히는 데에도 구구단만 한 것이 없다.

이번에는 다음과 같이 2 × 1 = 2부터 9 × 9 = 81까지 모두 출력해보자.

 

 

더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
 
int main()
{
    int num = 2, times;
 
    while (num < 10//num <= 9도 가능
    {
        times = 1;
        while (times < 10//times <= 9도 가능
        {
            printf("%d × %d = %d\n", num, times, num*times);
            ++times;
        }
        ++num;
        printf("\n");
    }
 
    return 0;
}
cs

 

 

이번엔 다음과 같이 출력해보자.

이왕이면 정렬도 해보자. (힌트: %8d, %-8d)

 

 

 

정렬하는 방법에는 여러가지가 있으니, 정렬만 되었다면 아래 코드와 달라도 상관 없다.

 

더보기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
int main()
{
    int num, times = 1;
 
    while (times < 10)
    {
        num = 2;
        while (num < 10)
        {
            printf("%d × %d = %-2d  ", num, times, num*times);
            ++num;
        }
 
        ++times;
        printf("\n");
    }
 
    return 0;
}
cs

 

 

 

3. do-while 문

 

do-while 문은 다음과 같은 형식으로 사용한다.

 

do 

{

실행문

} while(조건식);

...

 

while 문과의 차이가 보이는가?

while 문은 앞에서 조건식을 검사하고 내부 코드를 실행하는 반면,

do-while 문은 내부 코드를 실행한 후 뒤에서 조건식을 검사한다.

이로 인해 내부 코드를 무조건 한 번은 실행하게 된다.
 
그러니까 do-while 문의 실행 흐름은 다음과 같다.
 
반복할 코드 → 반복 조건을 거짓으로 만드는 연산 → 조건 검사 → 반복할 코드 → 
 
대부분의 경우 while 문을 do-while 문으로 대체할 수 있다.
그러나 while 문이 코드 작성에도, 이해에도 용이하기 때문에, 보통 while 문을 사용한다.
 
앞에서 본 구구단을 do-while 문으로 대체하면 다음과 같다.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
 
int main()
{
    int num = 1;
    int input;
 
    printf("몇 단?: ");
    scanf("%d"&input);
 
    do
    {
        printf("%d X %d = %d\n", input, num, input*num);
        ++num;
    } while (num < 10);
 
    return 0;
}
 
cs
 
이제 2 × 1 = 2부터 9 × 9 = 81까지 모두 출력해보자.
단, do-while 문을 사용해야 한다.
 
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
int main()
{
    int num, times = 1;
 
    do
    {
        num = 2;
        do
        {
            printf("%d × %d = %-2d  ", num, times, num*times);
            ++num;
        } while (num < 10);
 
        ++times;
        printf("\n");
    } while (times < 10);
 
    return 0;
}
cs

 

 

 

 

 

 

 

 

 

 

 

 

4. for 문

 

for 문은 다음과 같은 형식으로 사용한다.

 

for(초기식; 조건식; 증감식)

{    

실행문

}

 

초기식, 조건식, 증감식은 for 문의 필수 요소로, 각각 다음을 말한다.

 

초기식: *반복을 위한 변수 선언 또는 그 변수에 초기값 대입

조건식: 반복 조건

증감식: 반복 조건을 거짓으로 만드는 식

 

*: 이미 언급했듯이, 일부 컴파일러는 변수 선언을 중괄호 내부의 앞 부분에 두도록 하고 있다.

   따라서 for 문의 초기식 위치에서의 변수를 선언하면 에러가 발생할 수 있다.

 

 

다음 while 문은

 

times = 1;

while(times < 10)

{

printf("%d × %d = %d\n, num, times, num*times);    

++times;

 

다음 for 문으로 바꿔 쓸 수 있다.

 

for(times = 1; times < 10; ++times)

printf("%d × %d = %d\n, num, times, num*times); 

 

참고로 내부 코드가 한 줄이면 중괄호를 생략할 수 있다.

 

다음은 Hello, world!를 3번 출력하는 코드를 for 문으로 구현한 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main()
{
    int i;
 
    for (i = 0; i < 3++i)
        printf("Hello, world!\n");
 
    return 0;
}
cs

 

위 코드에서 for 문의 실행 흐름은 다음과 같다.

 

① 7행 - 초기식: i 를  0 으로 초기화한다.

② 7행 - 조건식: i < 3인가? → i = 0이므로 조건식 i < 3은 참이다.

③ 8행: "Hello, world!\n"를 출력한다.

④ 7행 - 증감식: i 값을 1 늘린다.

 

⑤ 7행 - 조건식: i < 3인가? → i = 1이므로 조건식 i < 3은 참이다.

⑥ 8행: "Hello, world!\n"를 출력한다.

⑦ 7행 - 증감식: i 값을 1 늘린다.

 

⑧ 7행 - 조건식: i < 3인가? → i = 2이므로 조건식 i < 3은 참이다.

⑨ 8행: "Hello, world!\n"를 출력한다.

⑩ 7행 - 증감식: i 값을 1 늘린다.

 

⑪ 7행 - 조건식: i < 3인가? → i = 3이므로 조건식 i < 3은 거짓이다. 반복을 멈춘다.

 

 

결국 for 문의 실행 흐름은 다음과 같다.

 

초기식 → 조건식 → 실행문 → 증감식 → 조건식 → 실행문 → 증감식 → 조건식 → 

 

그러다 조건식이 거짓이 되면 반복을 멈추는 것이다.

 

다음은 정수를 입력받고, 그 정수보다 작은 자연수의 합을 구하는 프로그램이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
int main()
{
    int num;
    int i;
    int sum = 0;
 
    printf("num: ");
    scanf("%d"&num);
 
    for (i = 1; i <= num; ++i) 
        sum += i;
 
    printf("%d보다 작은 자연수의 합: %d\n", num, sum);
 
    return 0;
}
cs

 

 

 

for 문 역시 중첩이 가능하다.

이미 두 번이나 했기 때문에 별다른 설명이 필요 없으리라 생각한다.

이번에도 구구단이다.

단, 직접 코드를 작성하는 것이 아니라 작성된 코드를 이해해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
int main()
{
    int i, j;
 
    for (i = 1; i <= 9++i)
    {
        for (j = 2; j <= 9++j)
        {
            printf("%d × %d = %-2d    ", j, i, i*j);
        }
 
        printf("\n");
    }
 
    return 0;
}
cs

 

위 코드를 실행하면 앞에서 작성한 코드와 같이 구구단이 출력된다.

 

이번엔 팩토리얼(factorial)이다.

정수 n을 입력받은 후 n!을 출력해보자. 단, n은 20 이하의 자연수다.

(Hint: int 형의 최대 값은 약 21억이고, 20!은 약 243경이다)

 

더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
 
int main()
{
    int n;
    int i;
    long long result = 1;
 
    printf("n: ");
    scanf("%d"&n);
 
    for (i = 1; i <= n; i++)
    {
        result *= i;
    }
 
    printf("result: %lld", result);
 
    return 0;
}
cs

 

 

참고로 초기식, 조건식, 증감식은 비울 수도 있다.

예를 들어 구구단의 경우 다음과 같이 바꿔 쓸 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
 
int main()
{
    int i, j;
 
    i = 1;
    for ( ; i <= 9; )
    {
        j = 2;
        for ( ; j <= 9; )
        {
            printf("%d × %d = %-2d    ", j, i, i*j);
            ++j;
        }
 
        printf("\n");
        ++i;
    }
 
    return 0;
}
cs

 

while 문으로 쓴 구구단과 흡사하지 않은가? 

하지만 빈 자리가 어쩐지 어색하다.

그래서 이런 스타일을 지양하자는 사람도 있다. 때문에 가급적이면 

초기식, 조건식, 증감식 자리를 모두 채우는 게 좋다.

특히 조건식 자리가 비게 되면, 무조건 참으로 간주해 무한 루프를 돌게 되므로 

주의해야 한다.

 

 

 

5. 언제 무엇을 써야 하나?

 

앞에서 보았듯이, 반복문에는 세 가지가 있고, 그 세 가지 모두 서로 바꿔 쓸 수 있다.

하지만 while 문을 쓸 때도 있고, do-while 문을 쓸 때도 있고, for 문을 쓸 때도 있다.

왜 그런 걸까? 어떤 경우에 while 문이 적합하고, 어떤 경우에 for 문이 적합한 걸까?

 

세 반복문 모두 반복한다는 점에서는 같지만, 보통 다음에 의해 적절한 것을 골라 쓴다.

 

반복을 결정하는 것은 상황 조건인가, 횟수 조건인가?

 

전자는 while 문이나 do-while 문이고, 후자는 for 문이다.

 

예를 들어 숫자를 입력받는데, -1을 입력받을 때까지 계속 입력받아야 한다고 해보자.

그리고 이걸 while 문과 for 문으로 작성해보자.

 

(while 문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
    int num = 0;
 
    while (num != -1)
    {
        printf("num: ");
        scanf("%d"&num);
    }
 
    return 0;
}
cs

 

(for 문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
    int num = 0;
 
    for( ; num != -1; )
    {
        printf("num: ");
        scanf("%d"&num);
    }
 
    return 0;
}
cs

 

앞에서 언급했듯이, for 문에서 초기식과 증감식 자리는 채우는 게 좋다.

그렇다고 다음과 같이 10번의 횟수 제한을 두면, 10번 안에 -1을 입력한다는 보장이 없으니

이것도 문제다.

 

따라서 이런 경우에는 while 문을 사용하는 게 좋다.

 

물론 for 문을 사용한다고 해서 에러가 발생하는 것은 아니다. 

하지만 while 문이 더 적합하다는 거다.

 

 

이번에는 5번만 입력받는다고 하자. 

그리고 이걸 while 문과 for 문으로 작성해보자.

 

(while 문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
int main()
{
    int num = 0;
    int i;
 
    i = 0;
    while (i < 5)
    {
        printf("num: ");
        scanf("%d"&num);
        ++i;
    }
 
    return 0;
}
cs

 

(for 문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
int main()
{
    int num = 0;
    int i;
 
    for(i = 0 ; i < 5++i;)
    {
        printf("num: ");
        scanf("%d"&num);
    }
 
    return 0;
}
cs

 

이 경우에는 for 문을 사용한 코드가 더 간결하다.

 

이번 역시 while 문을 사용한다고 해서 에러가 발생하는 것은 아니다. 

하지만 for 문이 더 적합하다는 거다.

 

 

그렇다면 while 문과 do-while 문은 어떤 차이가 있을까?

앞에서 말했듯이, 조건 검사의 시점 외에는 차이가 없다.

하지만 각자 더 적합한 경우는 있기 마련이다.

 

앞에서와 같이 -1을 입력받을 때까지 숫자를 입력받는다고 해보자.

그리고 이걸 while 문과 do-while 문으로 작성해보자.

 

(while 문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
    int num = 1;
 
    while (num != 0)
    {
        printf("num: ");
        scanf("%d"&num);
    }
 
    return 0;
}
cs

 

(do-while 문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
    int num;
 
    do
    {
        printf("num: ");
        scanf("%d"&num);
    } while (num != 0);
 
    return 0;
}
cs

 

이 경우에는 입력값을 검사해야 한다. 따라서 일단 입력을 받은 다음에 검사해야 한다.

그러니까 최소한 한 번은 입력을 받은 다음 조건 검사를 해야하는 것이다.

따라서 이 경우에는 do-while 문이 더 적절하다.

while 문으로 작성하기 위해서는 조건이 거짓이 되지 않도록, 입력받을 변수를 

적절한 값으로 초기화 해야만 한다.

 

 

 

 

 

 

'Programming > C' 카테고리의 다른 글

함수  (0) 2019.03.06
조건 분기  (0) 2019.03.04
입력과 출력  (0) 2019.03.02
연산자  (0) 2019.03.01
변수와 자료형  (0) 2019.02.26