for 반복문
for문의 초기화·조건·증감·본문이 순환하는 과정을 익히고 중첩 반복과 범위 기반 반복을 적절히 사용합니다.
프로그램에서 특정 작업을 반복적으로 수행해야 할 때 핵심이 되는 도구가 반복문(Loop Statements)입니다.
예를 들어 1부터 100까지의 숫자를 모두 더하기, 사용자가 종료를 입력할 때까지 계속 입력받기, 배열의 모든 요소 출력하기와 같은 작업들은 반복문 없이는 매우 비효율적이고 비실용적입니다.
이 장에서는 가장 널리 쓰이는 반복문인 for 문을 중심으로 사용 흐름을 정리합니다.
먼저 for 문을 시작 상태, 계속 조건, 반복마다의 상태 변화, 본문이 맞물려 도는 반복 사이클로 봅니다.
INIT ONCE · TEST BEFORE EACH PASS
for (초기화; 조건; 반복식)은 왼쪽부터 한 번씩 끝내는 목록이 아닙니다. 초기화만 한 번 실행하고, 이후에는 조건 → 본문 → 반복식 → 조건을 순환합니다.
-
초기화는 진입할 때 한 번
선언 또는 표현식으로 시작 상태를 만듭니다. 여기서 선언한 변수는 조건, 반복식, 본문에서 사용할 수 있고
for문을 벗어나면 범위를 벗어납니다. -
조건은 본문보다 먼저 검사
true이면 본문으로,false이면 루프 다음 문장으로 갑니다. 조건을 생략한for (;;)는 이 검사가true인 것과 같습니다. -
본문이 한 번의 작업을 수행
본문이 정상적으로 끝나면 반복식으로 갑니다. 중괄호를 쓰면 한 반복의 경계와 제어 이전 지점을 더 분명하게 읽을 수 있습니다.
-
반복식 뒤 조건을 다시 검사
++i나i += 2처럼 다음 상태를 만든 뒤 2단계로 돌아갑니다. 반복식을 생략했다면 필요한 상태 변화는 다른 곳에서 일어나야 합니다.
정상 완료
본문 → 반복식 → 조건 순서로 진행합니다.
현재 for의 continue
이 for를 직접 대상으로 하면 본문의 나머지를 건너뛰고 반복식을 실행한 뒤 조건을 다시 검사합니다.
현재 for의 break
더 안쪽 반복문이나 switch가 없어 이 for를 직접 대상으로 하면 반복식과 다음 조건 검사를 건너뛰고 루프 다음으로 이동합니다.
switch 안의 점프문은 가장 가까운 해당 구조를 대상으로 합니다. 반복 횟수는 시작값만으로 정해지지 않으므로 조건의 경계·방향과 반복식의 변화량, return·예외 경로까지 함께 확인합니다.반복문이란 무엇인가?
반복문은 프로그램의 특정 코드 블록을 여러 번 실행하도록 지시하는 제어문입니다.
반복문은 다음과 같은 주요 구성 요소를 가집니다.
초기화 (Initialization): 반복을 시작하기 전에 한 번만 수행되는 작업 (예: 반복 횟수를 세는 변수 초기화).
조건 (Condition): 반복을 계속할지 여부를 결정하는 조건입니다.
이 조건이 true인 동안 반복이 계속됩니다.
false가 되면 반복이 종료됩니다.
반복 표현식 (Iteration Expression): 본문이 정상적으로 끝나거나 현재 for를 직접 대상으로 하는 continue를 실행했을 때, 다음 조건 검사 전에 수행되는 작업입니다. 증가·감소뿐 아니라 다른 표현식도 쓸 수 있습니다.
반복 몸체 (Loop Body): 조건이 참일 때 반복적으로 실행될 코드 블록입니다.
C++은 for, while, do-while의 세 가지 주요 반복문을 제공합니다.
이 장에서는 for 문을 집중적으로 다룹니다.
for 문: 정해진 횟수만큼 반복
for 문은 반복 계약을 한 줄에 모아 쓰는 구조이므로, 초기화, 조건, 반복 표현식이 서로 맞는지 먼저 확인합니다.
for 문은 특히 반복 횟수가 명확하거나, 일정한 규칙에 따라 반복을 제어해야 할 때가장 적합하게 사용됩니다.
대부분의 경우, 루프 변수를 사용하여 반복 횟수를 추적합니다.
for (초기화; 조건; 증감) {
// 조건이 true인 동안 반복적으로 실행할 코드
}초기화:for문이 시작될 때 단 한 번 실행됩니다. 주로 루프 제어 변수를 선언하고 초기화하는 데 사용됩니다. (예:int i = 0;)조건: 매 반복이 시작되기 전에 평가됩니다. 이조건이true이면 반복 몸체가 실행되고,false이면for문이 종료됩니다. (예:i < 10;)반복 표현식: 본문이 정상적으로 끝나거나 현재for를 직접 대상으로 하는continue를 실행한 뒤 평가됩니다. 주로 루프 제어 변수의 값을 변경하여 다음 조건 검사에 쓸 상태를 만듭니다. 현재for를 종료하는break,return, 예외처럼 루프 밖으로 제어가 이동하면 실행되지 않습니다. (예:i++,i += 2){ }(중괄호): 조건이 참일 때 실행될 코드 블록입니다. 한 줄의 코드만 실행할 경우 생략할 수 있지만, 조건문과 마찬가지로 항상 사용하는 것이 좋습니다.
for 문의 실행 흐름
초기화 부분이 실행됩니다. (딱 한 번)
조건 부분이 평가됩니다.
만약 조건이 true이면, for 문의 반복 몸체({ } 안의 코드)가 실행됩니다.
반복 몸체가 정상적으로 끝나면, 반복 표현식이 실행됩니다. 현재 for를 직접 대상으로 하는 continue도 이 지점으로 이동합니다.
다시 2번 단계로 돌아가 조건 부분을 평가합니다.
조건이 false가 될 때까지 3, 4, 5번 과정을 반복합니다.
조건이 false가 되면 for 문이 종료되고 다음 코드가 실행됩니다.
이 흐름은 초기화 → 조건 검사 → 본문 실행 → 반복 표현식 → 재검사 → 종료의 사이클로 읽으면 좋습니다.
특히 반복 횟수를 셀 때는 시작값, 비교 연산자, 끝값이 서로 맞는지 확인해야 off-by-one 오류를 줄일 수 있습니다.
#include <iostream>
int main() {
// i를 1로 초기화하고, i가 5보다 작거나 같을 때까지 i를 1씩 증가시키며 반복
for (int i = 1; i <= 5; ++i) {
std::cout << i << " "; // 1 2 3 4 5
}
std::cout << std::endl;
return 0;
}#include <iostream>
int main() {
for (int i = 2; i <= 10; i += 2) { // i를 2부터 시작하여 2씩 증가
std::cout << i << " "; // 2 4 6 8 10
}
std::cout << std::endl;
return 0;
}#include <iostream>
int main() {
for (int i = 5; i >= 1; --i) { // i를 5부터 시작하여 1씩 감소
std::cout << i << " "; // 5 4 3 2 1
}
std::cout << std::endl;
return 0;
}for 문의 다양한 활용
for 문은 그 유연성 때문에 다양한 방식으로 활용될 수 있습니다.
여러 변수 초기화 및 반복 표현식:
선언에서는 쉼표로 같은 타입의 선언자를 나열할 수 있고, 반복 표현식에서는 콤마 연산자(,)로 여러 표현식을 차례로 평가할 수 있습니다.
#include <iostream>
int main() {
for (int i = 0, j = 10; i < 5; ++i, --j) {
std::cout << "i: " << i << ", j: " << j << std::endl;
}
/* 출력:
i: 0, j: 10
i: 1, j: 9
i: 2, j: 8
i: 3, j: 7
i: 4, j: 6
*/
return 0;
}초기화, 조건, 증감 부분 생략:
필요에 따라 for 문의 각 부분을 생략할 수 있습니다.
단, 세미콜론(;)은 반드시 유지해야 합니다.
- 초기화 생략: 루프 변수가 이미 이전에 선언 및 초기화된 경우.
- 조건 생략: 조건을
true로 간주하는 루프를 만들 때. 필요하면break,return, 예외 같은 제어 이전이나 외부 종료로 빠져나갑니다. - 증감 생략: 반복 몸체 내에서 루프 변수를 변경할 경우.
#include <iostream>
int main() {
int count = 0; // 초기화 부분 생략
for ( ; count < 3; ++count) {
std::cout << "Count: " << count << std::endl;
}
std::cout << "--- 무한 루프 예시 (break로 탈출) ---" << std::endl;
int limit = 0;
for ( ; ; ) { // 조건과 증감 모두 생략 -> 무한 루프
std::cout << "Current limit: " << limit << std::endl;
limit++;
if (limit >= 3) {
break; // limit이 3이 되면 루프 탈출
}
}
return 0;
}중첩 for 문 (Nested for Loops):
하나의 for 문 안에 다른 for 문을 포함하여 다차원적인 반복을 수행할 수 있습니다.
주로 2차원 배열 처리나 패턴 출력 등에 사용됩니다.
#include <iostream>
int main() {
// 구구단 2단부터 9단까지 출력
for (int i = 2; i <= 9; ++i) { // 바깥 루프: 단 (2단, 3단, ...)
std::cout << "--- " << i << "단 ---" << std::endl;
for (int j = 1; j <= 9; ++j) { // 안쪽 루프: 각 단의 곱셈
std::cout << i << " * " << j << " = " << (i * j) << std::endl;
}
std::cout << std::endl; // 각 단 출력 후 한 줄 띄기
}
// 별(*) 패턴 출력
for (int row = 0; row < 5; ++row) { // 5줄 반복
for (int col = 0; col <= row; ++col) { // 각 줄마다 row+1개의 별 출력
std::cout << "*";
}
std::cout << std::endl; // 한 줄 출력 후 줄바꿈
}
/* 출력:
*
**
***
****
*****
*/
return 0;
}범위 기반 for 문 - C++11 이후
C++11 표준부터는 배열이나 컨테이너의 모든 요소를 순회할 때 코드를 훨씬 간결하게 작성할 수 있는 범위 기반 for 문(Range-based for loop)이 도입되었습니다.
for (요소_타입 변수_이름 : 범위) {
// 범위의 각 요소에 대해 실행할 코드
}요소_타입 변수_이름: 범위의 역참조 결과로 초기화할 변수의 타입과 이름입니다. 이 절의 배열과std::vector<std::string>처럼 실제 요소 참조를 돌려주는 일반적인 값 컨테이너에서는auto가 요소 값을 새 변수로 받고,const auto&는 복사 없이 읽으며,auto&는 원본 요소를 수정합니다.std::vector<bool>처럼 프록시 참조를 반환하는 범위는 이 직관과 다를 수 있으므로 해당 반복자의 참조 타입을 확인해야 합니다.범위: 배열,std::vector,std::string등과 같이 반복 가능한(iterable) 객체입니다.
#include <iostream>
#include <string>
#include <vector> // std::vector를 사용하기 위해 포함
int main() {
int numbers[] = {10, 20, 30, 40, 50}; // C-스타일 배열
// 배열의 모든 요소 출력
for (int num : numbers) {
std::cout << num << " "; // 10 20 30 40 50
}
std::cout << std::endl;
std::vector<std::string> fruits = {"Apple", "Banana", "Cherry"}; // 벡터 (컨테이너)
// 벡터의 모든 요소 출력
for (const std::string& fruit : fruits) { // 요소를 변경하지 않을 것이므로 const 참조 사용
std::cout << fruit << " "; // Apple Banana Cherry
}
std::cout << std::endl;
// 요소 값 변경 예시
for (int& num : numbers) { // 참조(&)를 사용하여 실제 배열 요소에 접근
num += 1; // 각 숫자에 1을 더함
}
// 변경된 배열 출력
for (int num : numbers) {
std::cout << num << " "; // 11 21 31 41 51
}
std::cout << std::endl;
return 0;
}범위 기반 for 문은 범위 식을 한 번 평가한 뒤 시작과 끝을 얻어 순회합니다. 모든 요소를 차례로 다루는 목적이라면 직접 경계를 계산하지 않아 인덱스 오류를 줄일 수 있습니다. 반대로 위치 번호, 부분 범위, 역순, 간격, 여러 순회 상태를 직접 제어해야 한다면 일반 for가 더 분명합니다.
아래 다이어그램은 일반 for와 범위 기반 for의 선택 기준에 더해, range-for 요소를 복사할지 읽기 전용 참조로 받을지 원본 참조로 받을지 비교합니다.
CONTROL SHAPE · ELEMENT BINDING
먼저 위치와 진행 규칙을 직접 제어할지, 모든 요소를 차례로 받을지 고릅니다. 아래 바인딩 비교는 배열처럼 역참조 결과가 실제 요소 참조인 일반 값 컨테이너를 기준으로 합니다.
| 선택 | 알맞은 상황 | 직접 제어하는 것 | 주의할 의미 |
|---|---|---|---|
일반 for |
인덱스, 두 변수, 부분 범위, 역순, 간격이 문제의 의미일 때 | 초기 상태, 계속 조건, 반복마다의 상태 변화 | 경계와 변화 방향이 맞아야 하며, 컨테이너 인덱스는 유효 범위를 벗어나지 않아야 합니다. |
range-for + auto |
실제 요소 참조를 반환하는 범위에서 각 요소 값을 받을 때 | 범위만 제시하며 순회 위치는 구현이 관리 | 일반 값 컨테이너에서는 새 값 변수를 바꿔도 원본 요소가 바뀌지 않습니다. 프록시 참조 범위는 예외일 수 있습니다. |
range-for + const auto& |
일반 값 컨테이너의 실제 요소를 복사 없이 읽을 때 | 읽기 전용 참조로 현재 요소에 접근 | 큰 객체의 불필요한 복사를 피하면서 루프에서 원본을 수정하지 못하게 합니다. |
range-for + auto& |
수정 가능한 실제 요소 참조를 반환하는 범위를 순회할 때 | 수정 가능한 참조로 현재 요소에 접근 | 변경이 컨테이너에 남습니다. 순회 중 컨테이너 자체를 무효화할 수 있는 변경은 별도로 검토합니다. |
- 일반
for - 인덱스·부분 범위·역순·간격이 필요할 때 씁니다. 시작, 경계, 변화 방향을 함께 검증합니다.
- range-for +
auto - 일반 값 컨테이너에서는 새 값 변수를 받으므로 바꿔도 원본은 바뀌지 않습니다. 프록시 참조 범위는 예외일 수 있습니다.
- range-for +
constauto& - 일반 값 컨테이너의 실제 요소를 복사 없이 읽고, 루프에서 그 참조를 통한 수정은 허용하지 않습니다.
- range-for +
auto& - 수정 가능한 실제 요소 참조를 받아 제자리에서 바꿉니다. 순회를 무효화하는 컨테이너 변경은 피합니다.
std::vector<bool>처럼 프록시 참조를 쓰는 범위에서는 auto의 복사·수정 효과가 달라질 수 있어 반복자의 참조 타입을 확인합니다.