---
title: "for 는 적힌 순서대로 실행되지 않는다"
description: "괄호에 세 가지가 나란히 적혀 있지만 셋째는 본문이 끝난 뒤에 실행됩니다. 그래서 본문에서 보는 i 는 아직 증가 전입니다."
author: "유니얼"
pubDate: 2026-09-08
category: "programming/csharp/basics"
tags: ["C#", "기초"]
canonical: https://blog.unialgames.com/posts/csharp-for/
---
앞에서 반복문에는 시작, 계속 조건, 변화 세 가지가 있다고 했습니다.
`while` 은 이 셋을 세 곳에 흩어 적습니다.

```csharp
int i = 0;          // 시작 (반복문 밖)

while (i < 5)       // 계속 조건 (괄호 안)
{
    Console.WriteLine(i);
    i++;            // 변화 (블록 안 맨 아래)
}
```

세 가지가 멀리 떨어져 있으니 하나를 빠뜨려도 눈에 잘 안 띕니다.
특히 `i++` 는 블록 안에 다른 코드와 섞여 있어서, 코드가 길어지면 찾기도 어렵습니다.

> **셋을 괄호 하나에 모아 적은 것이 `for` 입니다.**

## for 는 이렇게 생겼다

<figure class="diagram">
<svg viewBox="0 0 680 200" role="img" aria-label="for 괄호 안의 세 부분이 각각 시작, 계속 조건, 변화에 해당한다는 그림">
<g font-family="var(--font-mono)" font-size="17">
<text x="40" y="40" fill="var(--accent)">for</text>
<text x="80" y="40" fill="var(--text-muted)">(</text>
<text x="94" y="40" fill="var(--text)">int i = 0;</text>
<text x="222" y="40" fill="var(--text)">i &lt; 5;</text>
<text x="304" y="40" fill="var(--text)">i++</text>
<text x="346" y="40" fill="var(--text-muted)">)</text>
</g>
<g fill="var(--bg)" stroke="var(--border)">
<rect x="60" y="88" width="180" height="72" rx="8"></rect>
<rect x="252" y="88" width="180" height="72" rx="8"></rect>
<rect x="444" y="88" width="180" height="72" rx="8"></rect>
</g>
<g stroke="var(--border)" stroke-width="1.4" fill="none">
<path d="M150 52 L150 88"></path>
<path d="M252 52 L252 70 L342 70 L342 88"></path>
<path d="M322 52 L322 80 L534 80 L534 88"></path>
</g>
<g text-anchor="middle">
<text x="150" y="114" font-size="14" fill="var(--accent)">1. 시작</text>
<text x="150" y="136" font-size="12" fill="var(--text-muted)">딱 한 번 실행</text>
<text x="342" y="114" font-size="14" fill="var(--accent)">2. 계속 조건</text>
<text x="342" y="136" font-size="12" fill="var(--text-muted)">매 회차 시작 전에 검사</text>
<text x="534" y="114" font-size="14" fill="var(--accent)">3. 변화</text>
<text x="534" y="136" font-size="12" fill="var(--text-muted)">매 회차 끝에 실행</text>
</g>
</svg>
<figcaption>세미콜론 두 개로 나뉜 세 칸. 순서대로 시작, 조건, 변화.</figcaption>
</figure>

```csharp
for (int i = 0; i < 5; i++)
{
    Console.WriteLine(i);
}
```

위의 `while` 코드와 하는 일이 완전히 같습니다.
달라진 것은 세 가지가 한 줄에 모여 있다는 것뿐입니다.
**한눈에 보이니 빠뜨리기 어렵습니다.**

칸을 나누는 것은 세미콜론입니다. 두 개가 항상 있어야 합니다.
`i` 라는 이름은 index 의 i 입니다. 관습이라 대부분 이렇게 씁니다.

## 세 칸은 적힌 순서대로 실행되지 않는다

여기가 이 글의 핵심입니다.

괄호 안에 `int i = 0; i < 5; i++` 이 왼쪽부터 나란히 적혀 있으니
그 순서대로 돌 것 같지만, 실제 순서는 다릅니다.

아래에서 `for` 의 세 칸을 일부러 세 줄로 나눠 적었습니다.
C# 은 줄바꿈을 신경 쓰지 않으니 이렇게 써도 똑같이 동작합니다.
커서가 어디로 가는지 보세요.

<x-flow>
<script type="application/json">
{
  "label": "for 의 실제 실행 순서",
  "dwell": 1.2,
  "lines": [
    "for (int i = 0;   // 시작",
    "     i < 3;       // 조건",
    "     i++)         // 변화",
    "{",
    "    Console.WriteLine(i);",
    "}",
    "Console.WriteLine(\"끝\");"
  ],
  "cases": [
    {
      "label": "i 가 0 부터 2 까지",
      "state": "i = 0",
      "path": [
        { "line": 0, "why": "딱 한 번입니다. 여기로는 다시 돌아오지 않습니다.", "state": "i = 0" },
        { "line": 1, "why": "본문에 들어가기 전에 검사합니다.", "verdict": "0 < 3" },
        { "line": 4, "why": "이 시점의 i 는 아직 증가하기 전입니다.", "out": "0" },
        { "line": 2, "why": "본문이 끝난 뒤에야 증가합니다. 괄호에는 두 번째 칸 다음에 적혀 있지만요.", "state": "i = 1" },
        { "line": 1, "why": "그리고 다시 조건으로 돌아옵니다. 첫 칸으로는 안 갑니다.", "verdict": "1 < 3" },
        { "line": 4, "out": "1" },
        { "line": 2, "state": "i = 2" },
        { "line": 1, "verdict": "2 < 3" },
        { "line": 4, "out": "2" },
        { "line": 2, "state": "i = 3" },
        { "line": 1, "why": "3 은 3 보다 작지 않습니다. 반복이 끝납니다.", "verdict": "거짓" },
        { "line": 6, "why": "본문을 건너뛰고 아래로 나갑니다.", "out": "끝" }
      ],
      "note": "시작 → 조건 → 본문 → 변화 → 조건 → 본문 → 변화 … 첫 칸은 다시 안 옵니다."
    }
  ]
}
</script>
</x-flow>

정리하면 이렇습니다.

| 순서 | 무엇 | 몇 번 |
| --- | --- | --- |
| 1 | 시작 (`int i = 0`) | 딱 한 번 |
| 2 | 조건 (`i < 3`) | 매 회차 시작 전 |
| 3 | 본문 | 조건이 참일 때만 |
| 4 | 변화 (`i++`) | **본문이 끝난 뒤** |

그리고 2번으로 돌아갑니다. 1번으로는 다시 가지 않습니다.

여기서 초보자가 가장 많이 헷갈리는 것이 4번입니다.
`i++` 가 괄호 안에서 조건 바로 다음에 적혀 있으니 조건 다음에 실행될 것 같지만,
**본문 다음**입니다.

그래서 **본문 안에서 보는 `i` 는 언제나 증가하기 전 값**입니다.
`i < 3` 인 반복문의 본문에서 `i` 는 0, 1, 2 이고 3은 절대 나오지 않습니다.

## 회차별로 값이 어떻게 도는가

`for (int i = 0; i < 5; i++)` 를 표로 펼치면 이렇습니다.

| 회차 | 조건 검사 | 본문의 i | 증가 후 |
| --- | --- | --- | --- |
| 1 | `0 < 5` 참 | 0 | 1 |
| 2 | `1 < 5` 참 | 1 | 2 |
| 3 | `2 < 5` 참 | 2 | 3 |
| 4 | `3 < 5` 참 | 3 | 4 |
| 5 | `4 < 5` 참 | 4 | 5 |
| - | `5 < 5` 거짓 | - | 종료 |

본문은 다섯 번 돌고, `i` 는 0부터 4까지 나옵니다.
`0` 부터 `5 미만`이라고 쓰면 **정확히 5번**입니다.

앞에서 인덱스가 0부터라고 했습니다.
`for (int i = 0; i < 길이; i++)` 형태가 그렇게 굳어진 이유입니다.
첫 칸이 0이고 마지막 칸이 `길이 - 1` 이니 딱 맞아떨어집니다.

## 언제 for 를 쓰고 언제 while 을 쓰나

**반복 횟수를 미리 알면 `for`, 모르면 `while`** 입니다.

```csharp
for (int i = 0; i < 10; i++)      // 열 번 돈다는 것이 코드에 적혀 있다
```

```csharp
while (!isGameOver)               // 몇 번 돌지는 실행해 봐야 안다
```

글자 수만큼, 배열 칸 수만큼처럼 세어서 도는 일은 `for` 입니다.
입력이 들어올 때까지, 적이 다 죽을 때까지처럼 세지 못하는 일은 `while` 입니다.

## 정리

- `for` 는 시작, 계속 조건, 변화를 괄호 하나에 모은 문법입니다. 세미콜론 두 개로 나눕니다.
- `while` 과 하는 일이 같습니다. 세 가지를 어디에 적느냐만 다릅니다.
- 실행 순서는 시작 → 조건 → 본문 → 변화 → 조건 → 본문 … 입니다.
- 변화는 괄호에서 두 번째 칸 다음에 적히지만 **본문이 끝난 뒤에** 실행됩니다.
- 그래서 본문 안의 `i` 는 항상 증가하기 전 값입니다.
- `0` 부터 `n 미만`까지 돌면 정확히 n번입니다.
- 횟수를 미리 알면 `for`, 모르면 `while`.