for 루프는 조건이 참인 동안 블록을 반복하며, 준비와 증가 단계를 루프 헤더에 씁니다. 정해진 반복 횟수나 배열의 모든 인덱스처럼 횟수를 셀 때 쓰는 루프입니다.
출력:
Lap 1 of 5
Lap 2 of 5
Lap 3 of 5
Lap 4 of 5
Lap 5 of 5
세 부분이 실행되는 순서
for (initializer; condition; iterator)는 정해진 순서로 실행됩니다:
- 초기화 식(
int i = 1)이 다른 무엇보다 먼저 한 번 실행됩니다. - 조건(
i <= 5)을 검사합니다. 거짓이면 루프가 끝나고 본문은 다시 실행되지 않습니다. - 본문이 실행됩니다.
- 반복자(
i++)가 실행되고, 2단계로 돌아갑니다.
조건은 매 반복 전에 검사되므로 for 루프는 한 번도 실행되지 않을 수 있습니다. for (int i = 10; i < 5; i++)는 본문에 들어가지 않습니다. 위의 루프는 다음 while 루프처럼 동작합니다:
int i = 1;
while (i <= 5)
{
Console.WriteLine($"Lap {i} of 5");
i++;
}
두 형태는 한 가지가 다릅니다. for 본문 안의 continue는 반복자를 여전히 실행하지만, 이 while 버전에서는 i++를 건너뛰므로 루프가 같은 i를 다시 검사하고 영원히 돌 수 있습니다. 초기화 식에서 선언한 변수는 루프 안에서만 존재합니다. 루프 뒤에 마지막 값이 필요하면 루프 전에 선언하세요: int i; for (i = 0; ...; i++) { }.
거꾸로 세기와 간격 지정
반복자는 어떤 식이든 될 수 있습니다. 거꾸로 세려면 감소시키고, 간격을 두려면 1보다 큰 수를 더하고, 등비수열에는 곱하세요:
출력:
3... 2... 1... liftoff
00 15 30 45
1 10 100 1000
반복자가 조건을 거짓으로 만드는 방향으로 움직이는지 확인하세요. for (int i = 0; i < 10; i--)는 10에서 멀어지는 방향으로 세며, 20억 번 반복한 뒤 i가 한 바퀴 돌아야만 멈춥니다.
인덱스로 배열 순회하기
배열은 Length를, 리스트는 Count를 제공하며, 올바른 인덱스는 0부터 그보다 하나 작은 값까지입니다. 인덱스는 foreach가 주지 않는 것을 줍니다. 위치, 이웃에 대한 접근, 그리고 다시 쓸 수 있는 권리입니다.
출력:
#1: 17.99
#2: 4.50
#3: 38.25
#4: 7.43
item 1 vs item 0: down
item 2 vs item 1: up
item 3 vs item 2: down
마지막 루프는 각 요소를 바로 앞 요소와 비교하므로 1에서 시작합니다. 배열 자체를 만들고, 정렬하고, 복사하는 방법은 배열 페이지에서 다룹니다.
여러 루프 변수
초기화 식은 같은 타입의 변수 여러 개를 선언할 수 있고, 반복자는 쉼표로 구분해 여러 변수를 갱신할 수 있습니다. 전형적인 용도는 서로를 향해 걸어가는 두 인덱스입니다:
출력:
racecar is a palindrome: True
9, 1, 8, 3
한 선언 안의 두 변수는 같은 타입이어야 합니다. int left = 0, right = 10은 되지만 int i = 0, string s = ""는 안 됩니다.
중첩 루프
루프 안의 루프는 바깥 루프의 반복마다 자기 범위 전체를 한 번씩 돕니다. 표와 격자가 대표적인 예입니다:
출력:
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
안쪽 본문은 16번(4 × 4) 실행됩니다. 중첩은 작업량을 빠르게 곱합니다. 각각 10,000개 항목을 도는 두 중첩 루프는 1억 번 반복합니다. 안쪽 루프의 break는 안쪽 루프만 빠져나갑니다. 둘 다 빠져나가는 방법은 break와 continue 페이지에서 보여 줍니다.
무한 루프: for(;;)
헤더의 세 부분은 모두 선택 사항입니다. 조건이 없으면 루프는 안에서 무언가가 빠져나갈 때까지 돕니다:
출력:
Month 1: 70 left
Month 2: 40 left
Month 3: 10 left
Overdrawn in month 4: -20
for (;;)와 while (true)는 같은 코드로 컴파일되므로 코드베이스에서 쓰는 쪽을 고르세요.
하나 차이 오류
가장 흔한 for 버그는 한 단계 너무 멀리 가는 조건입니다:
출력:
Ada
Grace
Linus
IndexOutOfRangeException at index 3
길이가 3인 배열의 인덱스는 0, 1, 2이므로 i < names.Length가 올바른 조건입니다. 반대쪽 버그는 i > 0으로 거꾸로 세는 것으로, 인덱스 0을 방문하지 않습니다. List<T>에서는 같은 실수가 대신 ArgumentOutOfRangeException을 던집니다.
순회하면서 항목 제거하기
앞으로 가는 루프 안에서 List<T>의 항목을 제거하면 뒤의 모든 요소가 한 칸씩 당겨지므로, 루프가 제거할 때마다 바로 다음 요소를 건너뜁니다:
출력:
forward: 5, 0, 3, 7
backward: 5, 3, 7
앞으로 가는 루프는 0 하나를 남겼습니다. 인덱스 1을 제거한 뒤 두 번째 0이 인덱스 1로 옮겨 왔지만, i++는 이미 인덱스 2로 넘어갔기 때문입니다. 거꾸로 돌면 제거가 이미 방문한 요소만 이동시키므로 이 문제가 없습니다. 한 줄짜리 대안으로 stock.RemoveAll(x => x == 0)이 같은 일을 합니다. foreach 루프는 제거를 아예 허용하지 않고 InvalidOperationException을 던집니다.
부동소수점 카운터
같음을 검사하는 double 루프 카운터는 피하세요. 0.1은 정확한 이진 표현이 없어서 열 번 더해도 정확히 1.0이 되지 않습니다:
for (double x = 0; x != 1.0; x += 0.1) // never ends: x skips past 1.0
{
}
정수로 세고 그 정수로부터 값을 계산하세요: for (int i = 0; i <= 10; i++) { double x = i / 10.0; }.
for와 foreach
| 필요한 것 | 사용 |
|---|---|
| 모든 요소를 순서대로 읽기 | foreach |
인덱스나 이웃(i - 1, i + 1) | for |
| 배열 요소에 대입 | for |
| 2씩 이동, 거꾸로 이동 | for |
순회하면서 List에서 제거 | for, 거꾸로 |
인덱서가 없는 컬렉션(HashSet, Dictionary, LINQ 결과) | foreach |
| 컬렉션 없이 N번 반복 | for |
배열에서는 두 루프가 사실상 같은 코드로 컴파일되므로, 속도가 아니라 가독성으로 고르세요.
자주 묻는 질문
C#에서 for 루프의 문법은 어떻게 되나요?
for (initializer; condition; iterator) { body }이며, 예를 들어 for (int i = 0; i < 5; i++) { ... }입니다. 초기화 식은 한 번 실행되고, 조건은 매 반복 전에 검사되며, 반복자는 매 반복 후에 실행됩니다. 조건이 처음으로 거짓이 되면 루프가 끝납니다.
C#에서 거꾸로 반복하려면 어떻게 하나요?
마지막 인덱스에서 시작해 감소시킵니다: for (int i = items.Length - 1; i >= 0; i--). > 0이 아니라 >= 0인 점에 주의하세요. 그렇지 않으면 첫 요소를 건너뜁니다. 거꾸로 반복하는 것은 순회하면서 List에서 항목을 제거하는 안전한 방법이기도 합니다.
C#에서 언제 foreach 대신 for를 써야 하나요?
인덱스가 필요할 때(이웃과 비교하거나, 배열에 다시 쓰거나, 1보다 큰 간격으로 이동할 때), 컬렉션을 순회하는 대신 횟수를 셀 때, 리스트에서 항목을 제거할 때 for를 쓰세요. 모든 요소를 순서대로 읽을 때는 foreach를 쓰세요. 더 짧고 틀릴 인덱스가 없습니다.
C#에서 무한 루프는 어떻게 쓰나요?
for (;;) { ... }나 while (true) { ... }입니다. for 헤더의 세 부분은 모두 선택 사항이며, 조건이 없으면 참으로 취급됩니다. 종료 조건을 만족하면 break나 return으로 루프를 빠져나가세요.
for 루프에서 IndexOutOfRangeException이 나는 이유는 무엇인가요?
조건이 인덱스가 길이에 도달하도록 허용하기 때문입니다. i <= array.Length는 마지막 요소 다음인 array[array.Length]를 방문합니다. 올바른 인덱스는 0부터 Length - 1까지이므로 조건은 i < array.Length여야 합니다(List라면 i < list.Count이며, 이 경우 대신 ArgumentOutOfRangeException이 발생합니다).