← C 강의 목록으로
⚙️
중급 (Intermediate)
for · while · do-while · break/continue

2단원 — 반복문

같은 작업을 여러 번 수행하는 도구가 **반복문**입니다. C에는 세 가지 반복문이 있고, 각각 어울리는 상황이 다릅니다.

forwhilebreak
소요 시간
1~2시간
난이도
📊 초급
선수 조건
🎯 중급 1단원
결과물
반복 흐름과 탈출 조건을 이해한다

이 강의에서 배우는 것

  • 1`for`, `while`, `do-while`을 상황에 맞게 선택한다.
  • 2중첩 반복문으로 2차원 패턴을 만든다.
  • 3`break`, `continue`로 흐름을 미세 제어한다.
  • 4무한 루프와 오프바이원(off-by-one) 오류를 피한다.

왜 세 가지나 필요할까?

세 반복문은 **언제 조건을 검사하느냐** 만 다릅니다.

text
 for (init; cond; step) { body }     ← 초기화·검사·증분이 한 줄, 횟수 명확할 때
 while (cond) { body }                ← 검사 먼저, 0회 실행 가능
 do { body } while (cond);            ← 본문 먼저, 최소 1회 실행 보장

세 가지 모두 다른 두 가지로 옮겨 쓸 수 있지만, **의도를 가장 잘 드러내는** 형태를 고르는 것이 좋습니다.

핵심 개념

1) `for` — 횟수가 명확할 때

c
for (int i = 0; i < 10; i++) {
    /* ... */
}

세 부분(`초기화 ; 조건 ; 증분`)이 한 줄에 모여 있어 "**i가 0부터 9까지**"가 한눈에 보입니다.

2) `while` — 조건만 있을 때

c
while (n > 0) {
    sum += n % 10;
    n /= 10;
}

"조건이 만족되는 동안" 반복. **0회도 가능**합니다.

3) `do-while` — 본문 먼저, 검사 나중

c
do {
    print_menu();
    scanf("%d", &choice);
} while (choice != 0);

본문이 **항상 한 번은** 실행됩니다. 메뉴 입력처럼 "최소 한 번은 묻기"에 적합.

4) `break` / `continue`

  • `break`: 가장 가까운 반복문을 즉시 종료.
  • `continue`: 본문의 나머지를 건너뛰고 다음 반복(증분/조건 평가)으로.
c
for (int i = 1; i <= 20; i++) {
    if (i % 2)  continue;     // 홀수는 건너뜀
    if (i == 14) break;        // 14에서 종료
    printf("%d ", i);
}

예제로 보기

예제 1 — `ex01_for.c` : 1부터 N까지의 합

c
long sum = 0;
for (int i = 1; i <= n; i++) sum += i;

**입력**: `10`

text
N 입력: 1부터 10까지의 합: 55

핵심: `i <= n`을 `i < n`으로 잘못 적으면 1+...+9=45가 됩니다 (오프바이원).

예제 2 — `ex02_while.c` : 자릿수 합

c
while (n > 0) {
    sum += n % 10;
    n /= 10;
}

**입력**: `1234`

text
정수 입력: 1234의 자릿수 합: 10

핵심: 자릿수 처리는 **`%`로 끝자리, `/`로 자릿수 줄이기**가 정석 패턴.

예제 3 — `ex03_do_while.c` : 메뉴 입력 (최소 1회)

본문 → 조건 검사 순서이므로 종료 조건(0)을 입력해도 메뉴는 한 번 보입니다.

예제 4 — `ex04_nested.c` : 구구단 (중첩 for)

c
for (int i = 2; i <= 9; i++)
    for (int j = 1; j <= 9; j++)
        printf("%d x %d = %2d\n", i, j, i * j);

**실행 결과 (앞부분)**

text
=== 2단 ===
2 x 1 =  2
2 x 2 =  4
2 x 3 =  6
2 x 4 =  8
2 x 5 = 10
2 x 6 = 12
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
=== 3단 ===
3 x 1 =  3
...

핵심: 바깥 루프가 한 번 돌 때 안쪽 루프가 **전부** 돕니다.

예제 5 — `ex05_break_continue.c` : 흐름 제어

1~20 중 짝수만 출력하다가 14에서 종료.

**실행 결과**

text
2 4 6 8 10 12

핵심: `continue`는 "건너뛰기", `break`는 "탈출".

다른 시각으로 보기 — 어떤 반복문을 고를까?

text
횟수가 미리 정해진다  → for
조건만 있고, 0회도 가능 → while
본문을 최소 1번은 돌려야 → do-while

세 가지 모두 다음처럼 동치 변환이 가능합니다.

c
/* for */                    /* while */
for (int i = 0; i < n; i++)  int i = 0;
    body;                    while (i < n) {
                                 body;
                                 i++;
                             }

자주 하는 실수

  1. **오프바이원(off-by-one)**: `i <= n` vs `i < n`을 헷갈려 1번 더/덜 도는 버그.
  2. **무한 루프**: `for (int i = 0; i < n; )` 처럼 증분을 잊으면 영원히 반복.
  3. **`while (n--)` 의 효과**: 0이 되면 false지만 `n--`은 한 번 더 평가됩니다. 의도를 점검.
  4. **반복 안에서 변수 재선언**: `for (int i = ...)`의 `i`는 루프 종료 후 사라집니다.
  5. **중첩 break**: `break`는 한 단계만 빠져나옵니다. 두 단계 빠지려면 플래그 변수나 함수 반환 사용.

정리

  • 세 반복문은 검사 시점만 다르며, 상황에 맞는 의도를 표현한다.
  • 횟수가 명확하면 `for`, 조건뿐이면 `while`, 최소 1회면 `do-while`.
  • `break`/`continue`로 미세 제어가 가능하지만 과용하면 가독성이 떨어진다.
  • 중첩 반복은 안쪽 루프가 바깥 한 번에 대해 전체 회전한다.
  • 종료 조건을 명확히 적어 무한 루프를 만들지 말 것.

직접 해 보기

bash
cd src
gcc -std=c11 -Wall -o ex01 ex01_for.c              && echo 10 | ./ex01
gcc -std=c11 -Wall -o ex02 ex02_while.c            && echo 1234 | ./ex02
gcc -std=c11 -Wall -o ex04 ex04_nested.c           && ./ex04 | head -20
gcc -std=c11 -Wall -o ex05 ex05_break_continue.c   && ./ex05

응용:

  • `ex01`을 `while`과 `do-while`로 각각 다시 작성해 보세요.
  • `ex04`에서 안쪽 루프를 `j <= i`로 바꾸면 출력은 어떻게 달라질까요?

💻 예제 (examples)

실제로 컴파일·실행해 결과를 확인할 수 있는 예제입니다.

ex01_for.c1부터 N까지의 합
CODE
#include <stdio.h>

int main(void) {
    int n;
    printf("N 입력: ");
    scanf("%d", &n);

    long sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += i;
    }
    printf("1부터 %d까지의 합: %ld\n", n, sum);
    return 0;
}
ex02_while.c자릿수 합
CODE
#include <stdio.h>

int main(void) {
    int n;
    printf("정수 입력: ");
    scanf("%d", &n);

    int original = n;
    int sum = 0;
    while (n > 0) {
        sum += n % 10;
        n /= 10;
    }

    printf("%d의 자릿수 합: %d\n", original, sum);
    return 0;
}
ex03_do_while.c메뉴 입력 (최소 1회)
CODE
#include <stdio.h>

int main(void) {
    int choice;
    do {
        printf("\n=== 메뉴 ===\n");
        printf("1. 인사\n");
        printf("2. 시간\n");
        printf("0. 종료\n");
        printf("선택: ");
        if (scanf("%d", &choice) != 1) break;

        switch (choice) {
            case 1: printf("안녕하세요!\n"); break;
            case 2: printf("지금은 학습 시간입니다.\n"); break;
            case 0: printf("종료합니다.\n"); break;
            default: printf("잘못된 선택\n");
        }
    } while (choice != 0);

    return 0;
}
ex04_nested.c구구단 (중첩 for)
CODE
#include <stdio.h>

int main(void) {
    for (int i = 2; i <= 9; i++) {
        printf("=== %d단 ===\n", i);
        for (int j = 1; j <= 9; j++) {
            printf("%d x %d = %2d\n", i, j, i * j);
        }
    }
    return 0;
}
ex05_break_continue.c흐름 제어
CODE
#include <stdio.h>

int main(void) {
    /* 1~20 중 짝수만 출력하다가 14를 만나면 종료 */
    for (int i = 1; i <= 20; i++) {
        if (i % 2 != 0) continue;   // 홀수는 건너뜀
        if (i == 14)    break;      // 14에서 종료
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}
▶ 실행 결과
2 4 6 8 10 12

📝 과제 (exercises)

직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.

과제 1

문제 1 (hw01.c)

목표: 입력 N에 대해 N!(팩토리얼)을 출력하세요. 단, 결과는 `long long` 타입.

요구사항
  • 파일명: hw01.c
입출력 예시
N 입력: 10
10! = 3628800
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int n;
    printf("N 입력: ");
    scanf("%d", &n);

    long long fact = 1;
    for (int i = 2; i <= n; i++) {
        fact *= i;
    }
    printf("%d! = %lld\n", n, fact);
    return 0;
}
▶ 실행 결과
N 입력: 10
10! = 3628800
과제 2

문제 2 (hw02.c)

목표: N을 입력받아 별로 다음과 같은 직각삼각형을 그리세요. (N=4 예시)

요구사항
  • 파일명: hw02.c
입출력 예시
*
**
***
****
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int n;
    printf("N 입력: ");
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < i; j++) putchar('*');
        putchar('\n');
    }
    return 0;
}
▶ 실행 결과
*
**
***
****
과제 3

문제 3 (hw03.c)

목표: 2~100 사이의 **소수**를 모두 출력하세요. (한 줄에 공백으로 구분)

요구사항
  • 파일명: hw03.c
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    for (int n = 2; n <= 100; n++) {
        int prime = 1;
        for (int d = 2; d * d <= n; d++) {
            if (n % d == 0) { prime = 0; break; }
        }
        if (prime) printf("%d ", n);
    }
    putchar('\n');
    return 0;
}
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗