---
title: "모든 반복문은 세 부분으로 되어 있다"
description: "어디서 시작하고, 언제까지 돌고, 매번 무엇이 변하는가. 셋 중 하나가 빠지면 영원히 돌거나 한 번도 안 돕니다."
author: "유니얼"
pubDate: 2026-09-08
category: "programming/csharp/basics"
tags: ["C#", "기초"]
canonical: https://blog.unialgames.com/posts/csharp-while/
---
앞에서 흐름을 바꾸는 방법은 두 가지뿐이라고 했습니다.
갈라지거나, 되돌아가거나. 지금까지 갈라지기를 봤으니 이제 되돌아가기입니다.

1부터 5까지 출력하는 코드를 조건문만으로 써 보면 이렇게 됩니다.

```csharp
Console.WriteLine(1);
Console.WriteLine(2);
Console.WriteLine(3);
Console.WriteLine(4);
Console.WriteLine(5);
```

100까지라면 100줄입니다. 몇 번까지인지 실행해 봐야 안다면 아예 쓸 수가 없습니다.

> **같은 자리로 되돌아가서 조건이 거짓이 될 때까지 반복하는 문법이 반복문입니다.**

## 반복문에는 항상 세 가지가 있다

문법을 보기 전에 이것부터 짚고 갑니다.
`while` 이든 `for` 이든, 반복문에는 예외 없이 세 가지가 들어 있습니다.

<figure class="diagram">
<svg viewBox="0 0 680 210" role="img" aria-label="반복문의 세 부분. 시작, 계속 조건, 변화가 순환하는 그림">
<g fill="var(--bg)" stroke="var(--border)">
<rect x="20" y="30" width="180" height="54" rx="8"></rect>
<rect x="250" y="30" width="180" height="54" rx="8"></rect>
<rect x="250" y="130" width="180" height="54" rx="8"></rect>
</g>
<g stroke="var(--text-muted)" stroke-width="1.4" fill="none">
<path d="M200 57 L242 57"></path>
<path d="M340 84 L340 124"></path>
<path d="M250 157 L214 157 L214 70 L242 70"></path>
</g>
<g fill="var(--text-muted)" stroke="none">
<path d="M242 57 l-9 -5 l0 10 z"></path>
<path d="M340 124 l-5 -9 l10 0 z"></path>
<path d="M242 70 l-9 -5 l0 10 z"></path>
</g>
<g text-anchor="middle">
<text x="110" y="52" font-size="14" fill="var(--accent)">1. 시작</text>
<text x="110" y="72" font-size="12" fill="var(--text-muted)">딱 한 번</text>
<text x="340" y="52" font-size="14" fill="var(--accent)">2. 계속 조건</text>
<text x="340" y="72" font-size="12" fill="var(--text-muted)">매 회차 시작 전에 검사</text>
<text x="340" y="152" font-size="14" fill="var(--accent)">3. 변화</text>
<text x="340" y="172" font-size="12" fill="var(--text-muted)">조건에 가까워지게 만든다</text>
</g>
<text x="470" y="62" font-size="13" fill="var(--text-muted)">거짓이면</text>
<text x="470" y="80" font-size="13" fill="var(--text-muted)">여기서 빠져나간다</text>
<path d="M432 57 L462 57" stroke="var(--border)" stroke-width="1.4" fill="none"></path>
</svg>
<figcaption>셋 중 하나라도 빠지면 반복문이 제대로 안 돈다.</figcaption>
</figure>

계단을 오르는 것과 같습니다. 1층에서 출발해서(시작), 5층에 닿을 때까지(조건),
한 번에 한 칸씩(변화).

`while` 과 `for` 의 차이는 이 세 가지를 **어디에 적느냐**뿐입니다.
`while` 은 세 곳에 흩어 적고, `for` 은 한 줄에 모아 적습니다.

## while 은 이렇게 생겼다

```csharp
while (조건)
{
    조건이 참인 동안 반복할 코드
}
```

`if` 와 생김새가 똑같습니다. 키워드만 다릅니다.
다른 점은 블록이 끝났을 때입니다. `if` 는 아래로 지나가고,
`while` 은 조건을 다시 보러 위로 올라갑니다.

세 가지 중 `while` 괄호에 적히는 것은 **조건 하나뿐**입니다.
시작은 위에, 변화는 블록 안에 직접 적어야 합니다.

```csharp
int count = 1;          // 1. 시작

while (count <= 3)      // 2. 계속 조건
{
    Console.WriteLine(count);
    count++;            // 3. 변화
}
```

## 조건을 먼저 보고, 그다음 들어간다

<x-flow>
<script type="application/json">
{
  "label": "while 한 바퀴씩",
  "dwell": 1.2,
  "lines": [
    "int count = 1;",
    "while (count <= 3)",
    "{",
    "    Console.WriteLine(count);",
    "    count++;",
    "}",
    "Console.WriteLine(\"끝\");"
  ],
  "cases": [
    {
      "label": "count = 1 부터",
      "state": "count = 1",
      "path": [
        { "line": 0, "why": "시작 값을 정합니다. 여기로는 다시 돌아오지 않습니다.", "state": "count = 1" },
        { "line": 1, "why": "본문에 들어가기 전에 먼저 검사합니다.", "verdict": "1 <= 3" },
        { "line": 3, "why": "지금 count 값을 찍습니다.", "out": "1" },
        { "line": 4, "why": "값을 하나 늘립니다. 이게 없으면 조건이 영영 안 바뀝니다.", "state": "count = 2" },
        { "line": 1, "why": "블록이 끝나면 아래로 가지 않고 조건으로 돌아옵니다.", "verdict": "2 <= 3" },
        { "line": 3, "why": "두 바퀴째입니다.", "out": "2" },
        { "line": 4, "state": "count = 3" },
        { "line": 1, "why": "3 은 아직 3 이하입니다. 한 바퀴 더 돕니다.", "verdict": "3 <= 3" },
        { "line": 3, "out": "3" },
        { "line": 4, "state": "count = 4" },
        { "line": 1, "why": "4 는 3 이하가 아닙니다. 여기서 반복이 끝납니다.", "verdict": "거짓" },
        { "line": 6, "why": "블록을 건너뛰고 아래로 나갑니다.", "out": "끝" }
      ],
      "note": "조건 검사 → 본문 → 변화 → 다시 조건 검사. 이 순서가 계속 돕니다."
    }
  ]
}
</script>
</x-flow>

조건을 **본문에 들어가기 전에** 봅니다. 그래서 처음부터 거짓이면
본문에 한 번도 들어가지 않습니다.

```csharp
int count = 10;

while (count <= 3)
{
    Console.WriteLine(count);   // 한 번도 실행되지 않습니다
    count++;
}
```

에러가 아닙니다. 출력이 없을 뿐입니다.

## 변화가 없으면 영원히 돈다

세 가지 중 변화를 빼먹으면 이렇게 됩니다.

```csharp
int count = 1;

while (count <= 3)
{
    Console.WriteLine(count);
    // count++ 를 빠뜨렸습니다
}
```

`count` 는 영원히 1입니다. 조건은 영원히 참입니다. 프로그램이 멈추지 않습니다.
콘솔에 1이 끝없이 찍히고, 직접 끄기 전까지는 안 끝납니다.
터미널이라면 `Ctrl` + `C` 로 멈춥니다.

무한 루프가 되는 경우는 대체로 셋 중 하나입니다.

| 원인 | 예 |
| --- | --- |
| 변화가 없다 | `count++` 를 빠뜨렸다 |
| 방향이 반대다 | `count--` 를 써서 조건에서 멀어진다 |
| 조건이 항상 참이다 | `while (true)` 인데 나갈 길이 없다 |

**반복문을 쓸 때 확인할 것은 하나입니다. 무엇이 이 조건을 거짓으로 만드는가.**
그 답이 코드 안에 없으면 무한 루프입니다.

## 일부러 무한 루프를 쓰기도 한다

게임 루프나 서버처럼 "끌 때까지 계속 도는" 것이 목적일 때가 있습니다.
이때는 `while (true)` 를 씁니다.

```csharp
while (true)
{
    string input = Console.ReadLine();

    if (input == "exit")
    {
        break;      // 여기서 나갑니다
    }

    Console.WriteLine("입력: " + input);
}
```

조건 자리에 아예 `true` 를 박아 두고, 나가는 길을 블록 안에 만듭니다.
`break` 는 반복문을 그 자리에서 끝내는 키워드입니다. 뒤에서 자세히 봅니다.

의도한 무한 루프와 실수로 만든 무한 루프의 차이는 **나갈 길이 있느냐**입니다.
`while (true)` 를 쓰면서 `break` 를 안 넣었다면 그건 그냥 버그입니다.

## 정리

- 반복문에는 시작, 계속 조건, 변화 세 가지가 항상 있습니다.
- `while` 은 괄호에 조건만 적습니다. 시작은 위에, 변화는 블록 안에 직접 적습니다.
- 조건을 본문보다 먼저 봅니다. 처음부터 거짓이면 본문은 한 번도 실행되지 않습니다.
- 블록이 끝나면 아래로 가지 않고 조건으로 돌아옵니다.
- 조건을 거짓으로 만들 무언가가 없으면 무한 루프입니다.
- `while (true)` 는 나갈 길(`break`)을 블록 안에 만들어 두고 씁니다.