본문 바로가기

Programming Language/C

반복문

1. for문

for문은 내부의 조건에 부합하면 계속해서 특정한 구문을 실행하는 특성을 가지고 있습니다. 반복문에서 탈출하려면, 반복문을 탈출하고자 하는 위치에 break구문을 삽입하면 됩니다. for문의 형식은 아래와 같습니다.

for (초기식; 조건식; 증감식) {
    // 반복할 코드
}

초기식이 가장 먼저 실행됩니다. 그 뒤 조건식으로 가서 해당 조건을 만족하면 반복할 코드를 실행합니다. 조건을 만족하지 못한다면 for문을 종료시킵니다. 조건식을 만족해서 코드가 실행되었다면 이후 증감식을 실행시킨 뒤 다시 조건식을 판별합니다.
1부터 100까지의 정수를 출력하는 예제를 작성해보면서 상세히 다루어 보겠습니다.

1.1. 예제1: 0부터 100까지의 정수를 출력하기

#include <stdio.h>

int main(void) {
    for (int i = 0; i <= 100; i++) {
        printf("%d\n", i);
    }
    system("pause");
}

결과:

1
2
3
...
99
100
계속하려면 아무 키나 누르십시오 . . .

초기식에서는 int i = 0; 과 같이 반복에 사용할 변수를 선언하고 0으로 초기화했습니다. 여기서 초기식은 반드시 for문 안에 있을 필요는 없습니다. for문 바깥으로 먼저 초기식을 선언해주었다면 문법오류가 발생하지 않습니다.
100까지의 정수를 출력한다고 했기 때문에 조건식은 100보다 작거나 같다고 선언을 하고 증감식은 1씩 증가하도록 해주었습니다.
반복문이 처음 실행되면 i에는 0이 들어가고 i가 100보다 작거나 같은지 판단합니다. 0은 100보다 작거나 같기 때문에 참이므로 반복할 코드를 실행합니다. 그리고 i++를 실행해서 i를 1증가시킵니다. 1만큼 증가한 i는 조건식으로 돌아가서 100보다 작거나 같은지 판단하고 참이면 반복할 코드를 실행합니다. 이러한 과정을 반복하다가 i가 101이 되면 조건식에 부합하지 않기 때문에 거짓이 되므로 반복문을 종료합니다.

1.2. 예제2: 1부터 N까지의 합 출력하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, sum = 0;
    printf("n의 값을 정해주세요. ");
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        sum = sum + i;
    }
    printf("1부터 %d까지의 합은 %d입니다.\n", n, sum);
    system("pause");
    return 0;
}

결과:

n의 값을 정해주세요. 5
1부터 5까지의 합은 15입니다.
계속하려면 아무 키나 누르십시오 . . .

n까지의 합을 구하는 것이므로 변수 n과 sum을 만들어줍니다. 사용자에게 "n의 값을 정해주세요."를 출력함으로써 사용자가 변수 n의 값을 입력할 수 있게 만들고, scanf()함수를 통해서 n값을 받습니다. 이후에 for문을 통해서 i를 1부터 n까지 반복을 시킵니다. 반복을 하면서 sum에 계속해서 숫자를 더할 수 있도록 sum = sum + i; 와 같은 식을 작성합니다.

1.3. 무한 루프

무한 루프는 종료 조건이 없어 한없이 반복되는 반복문을 말합니다. 무한 루프를 의도적으로 발생시키는 경우보다 개발자의 실수로 인해 발생하는 경우가 일반적입니다. 즉, 조건문에서 조건이 항상 참값인 경우에 무한 루프가 발생할 수 있다는 것입니다. 바로 위에서 보았던 코드에서는 사용자가 입력한 n값까지만 반복하게 했기 때문에 사용자가 입력한 n값에 도달하면 반복은 종료가 됩니다. 여기서 만약 "n값까지"라는 조건이 없었다면 반복은 계속 실행되었을 것입니다.

1.3.1. 무한 루프 예제1

#include <stdio.h>

int main(void) {
    for (;;) {
        printf("Hello World\n");
    }
    system("pause");
}

위의 예제 코드를 보면 for문에 아무런 조건이 없는 것을 알 수 있습니다. 초기식도 없고, 조건식도 없고, 증감식도 없습니다. 조건문의 내용이 없다는 것은 항상 참이 되는 것입니다. 따라서 컴퓨터는 종료조건이 없기 때문에 끝없이 "Hello World"를 출력하게 됩니다.

1.3.2. 무한 루프 예제2

#include <stdio.h>

int main(void) {
    for (int i=0; i<=100; i--) {
        printf("Hello World\n");
    }
    system("pause");
}

for문을 이용할 때는 조건이 반드시 끝나야 합니다. 하지만 위의 예제에서 for문은 0부터 100까지 반복을 하라고 했으나 i의 값은 1씩 감소하라고 되어 있습니다. 결과적으로 i <= 100의 조건을 항상 만족하는 참인 경우이므로 이 코드 또한 무한 루프를 발생시킵니다.

1.3.3. 무한 루프 예제3: -1이 입력될 때까지 더하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

// 사용자가 -1을 입력할 때까지 더하기
int main(void) {
    int sum = 0;
    for (;;) {
        int x;
        printf("숫자를 입력하세요: ");
        scanf("%d", &x);
        if (x == -1) break;
        sum += x;
    }
    printf("지금까지 더한 값은 %d입니다.\n", sum);
    system("pause");
}

결과:

숫자를 입력하세요: 1
숫자를 입력하세요: 2
숫자를 입력하세요: 3
숫자를 입력하세요: -1
지금까지 더한 값은 6입니다.
계속하려면 아무 키나 누르십시오 . . .

사용자가 입력한 값을 받아 계속해서 더하는 프로그램입니다. for문에는 아무 조건이 없고, 심지어 조건식 또한 없기 때문에 무한루프를 발생시킵니다. 그러나 사용자가 -1을 입력할 경우 break 구문이 작동하여 무한루프를 탈출할 수 있습니다.

  • 위 코드에는 for문의 조건을 for(;;)과 같이 했으나 for( ; 1; )과 같이 작성해도 좋습니다. 컴퓨터에서는 0을 제외한 모든 숫자를 참으로 인식하기 때문에 조건식이 1이 되면 항상 참이 된다는 것을 의미합니다. 따라서 동일하게 무한루프가 발생합니다.
  • sum += x;는 sum에 x로부터 받은 값을 계속 더한다는 뜻입니다. sum = sum + x;와 동일합니다.

2. while문

while문은 특정한 조건에 부합할 때에 한해서 계속해서 특정한 구문을 실행하는 명령어입니다. 또한, 반복문을 탈출하고자 하는 위치에 break 구문을 삽입하여 반복을 벗어납니다. while문은 아래와 같은 형태를 가집니다.

while (조건) {
    // 반복적으로 실행할 부분
}

2.1. 특정문자를 n번 출력하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

// 특정 문자를 n번 출력하기
int main(void) {
    int n;
    char a;
    printf("반복할 문자와 반복횟수를 순서대로 입력하세요. ");
    scanf("%c %d", &a, &n);
    while (n--) {
        printf("%c ", a);
    }
    system("pause");
    return 0;
}

결과:

반복할 문자와 반복횟수를 순서대로 입력하세요. V 12
V V V V V V V V V V V V 계속하려면 아무 키나 누르십시오 . . .

먼저 변수 n과 문자 a를 선언한 이후에 각각 사용자로부터 입력을 받습니다. while문에 조건을 n-- 로 달아두어 1씩 계속해서 감소하면서 특정한 구문을 실행시킵니다. 컴퓨터는 0을 제외한 모든 숫자를 참으로 인식한다는 점을 생각했을 때, while문의 조건이 계속해서 1씩 감소하다가 0이 되는 순간 거짓이 되므로 반복은 종료가 되는 것입니다. 따라서 printf() 함수를 n번 반복할 수 있는 것입니다.

처음 while문이 실행되면, 현재의 조건이 참인지 검사를 하고 만약 조건이 참이라면 printf() 함수를 실행시킵니다. 실행시킨 뒤 다시 while문의 조건으로 돌아옵니다. 이 때 돌아오는 순간 n은 1만큼 감소합니다. 그 뒤 감소된 n이 여전히 참이라면 다시 코드를 실행하고, 그렇지 않다면 반복을 종료하여 결과적으로 총 n번 문자가 출력됩니다.

2.2. 특정 숫자의 구구단 출력하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

// 특정 숫자의 구구단 출력하기
int main(void) {
    int n;
    int i = 1;
    printf("어떤 수의 구구단을 출력하시겠습니까? ");
    scanf("%d", &n);
    while (i <= 9) {
        printf("%d * %d = %d\n", n, i, n * i);
        i++;
    }
    system("pause");
    return 0;
}

결과:

어떤 수의 구구단을 출력하시겠습니까? 5
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
5 * 6 = 30
5 * 7 = 35
5 * 8 = 40
5 * 9 = 45
계속하려면 아무 키나 누르십시오 . . .

i를 1로 초기화했고 while문의 조건은 9까지 반복하는 것입니다. i++를 while문 안에 넣었기 때문에 1씩 증가하면서 i=9까지 도달할 수 있습니다. i++를 넣지 않았을 경우 i는 계속 1이라는 값을 가지고, i<=9 조건을 항상 만족시키게 되어 무한루프가 발생하게 됩니다.


3. 중첩된 반복문

중첩된 반복문은 말그대로 여러 개의 반복문이 중첩된 형태를 말하는 것입니다. 반복문 내부에 다른 반복문이 존재하는 형태의 반복문으로, 반복문이 중첩될수록 연산 횟수는 제곱 형태로 늘어나게 됩니다.

3.1. while을 이용한 전체 구구단 출력하기

#include <stdio.h>

int main(void) {
    int i = 1;
    while (i <= 9) {
        int j = 1;
        while (j <= 9) {
            printf("%d * %d = %d\n", i, j, i * j);
            j++;
        }
        printf("\n");
        i++;
    }
    system("pause");
}

i는 1부터 출발해서 9번 큰 while문을 반복하는 것이고, 한 번 i가 1씩 증가할 때마다 j는 9번씩 반복되는 것입니다. 즉, i는 1단, 2단과 같이 증가하는 것이고 j는 각 단마다 9번씩 곱할 값을 출력하는 것입니다. 또한 한 번 단이 출력될 때마다 줄바꿈을 출력해서 각각의 단을 구분할 수 있게 합니다.

이 부분을 공부하면서 j를 초기화시키는 부분을 i를 초기화한 곳 바로 밑에서 초기화시킨다면 조금 더 깔끔한 코드가 되지 않을까라는 생각에 아래와 같이 코드를 변형하고 프로그램을 실행시켜보았습니다. 실행 전에는 동일한 결과가 출력될 것이라는 생각을 했으나 실제로 나온 결과는 많이 다른 결과를 보여주었습니다.

#include <stdio.h>

int main(void) {
    int i = 1;
    int j = 1;
    while (i <= 9) {
        while (j <= 9) {
            printf("%d * %d = %d\n", i, j, i * j);
            j++;
        }
        printf("\n");
        i++;
    }
    system("pause");
}

위 코드를 실행시켜 보면 구구단의 1단만 출력되고 그 밑으로 개행만 9번 실행되는 결과를 얻을 수 있습니다. 분명 모든 변수의 초기화를 마쳤는데 왜 1단 밖에 나오지 않는지에 대해 고민을 해보았습니다. 고민의 결과 변수 j는 사실 제대로 초기화된 것이 아니었습니다. 분명 처음에는 j가 1로 초기화된 것이 맞습니다. 그러나 변수 j가 들어간 반복문이 처음 1회차 실행이 완료되면 j는 10인 상태입니다. 값이 10이 들어간 j는 다시 반복문으로 들어가지만 j <= 9 라는 조건에 부합하지 못해서 반복문은 종료가 됩니다. 이제 남은 반복문인 변수 i에 대한 반복문은 개행을 한 번 실행하고 i는 1만큼 증가합니다. 중첩된 while문은 이미 종료가 되었으니 다시 개행을 하고 i는 1만큼 증가합니다. 이러한 과정을 i는 9가 될 때까지 반복을 실행하니 구구단 1단만 출력된 뒤 개행이 9번 실행된 결과가 나온 것이었습니다.
위의 코드에서 j를 초기화한 식을 옮기지 않고 9단까지 출력하려면 while(j <= 9) 바로 위에 int j = 1;을 한 번 더 선언해주면 됩니다. 그러나 이렇게 코드를 작성할 경우 j에 대한 초기화가 불필요하게 1번 더 추가되기 때문에 처음 작성했던 코드대로 작성하는 것이 가장 깔끔한 코드가 되겠습니다.

3.2. for을 이용한 전체 구구단 출력하기

#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            printf("%d * %d = %d\n", i, j, i * j);
        }
        printf("\n");
    }
    system("pause");
}

3.3. for문과 while문의 관계

  • 위에서 구구단 출력문제를 for문과 while문으로 작성해보았습니다. 그리고 둘의 결과는 모두 같습니다. 이와 같이 for문과 while문은 서로 치환이 가능합니다. 모든 for문은 while문으로 변경이 가능하고, 모든 while문은 for문으로 변경이 가능합니다.
  • 우리가 작성한 C언어 코드가 컴파일이 이루어지면서 기계어로 변환이 되었을 때는 결국 동일한 명령어로 동작합니다. 따라서, for문과 while문은 내부적으로 동일하게 동작한다고 볼 수 있습니다.