while과 do-while 반복문
while과 do-while의 조건 검사 시점을 비교하고 횟수를 모르는 반복과 입력 검증 흐름을 안전하게 작성합니다.
때로는 반복 횟수를 미리 알 수 없거나, 특정 조건이 만족될 때까지 계속 반복해야 하는 경우가 있습니다.
예를 들어 사용자가 올바른 값을 입력할 때까지 계속 입력받거나, 파일의 끝에 도달할 때까지 데이터를 읽는 것과 같은 상황이 있을 수 있습니다.
이런 경우에 적합한 반복문이 바로 while 문과 do-while 문입니다.
이 장에서는 이 두 반복문의 특징과 사용법을 다룹니다.
먼저 while과 do-while을 조건을 검사하는 시점이 다른 반복문으로 나눠 봅니다.
PRE-TEST · POST-TEST
while은 먼저 검사하고 do-while은 먼저 실행한다
둘 다 검사 결과가 true이면 반복하고 false이면 빠져나옵니다. 갈리는 지점은 첫 검사보다 본문이 앞에 있는지입니다.
while (조건) { 본문 }
본문 전에 검사하는 선검사 반복
-
조건 검사
조건 값을
bool로 문맥 변환합니다. 처음부터false면 본문을 건너뜁니다. -
true일 때 본문 실행본문의 끝에 도달하면 다음 조건 검사로 되돌아갑니다.
-
false면 종료while다음 문장으로 제어가 이어집니다.
최소 실행 횟수: 0회
do { 본문 } while (식);
본문 뒤에 검사하는 후검사 반복
-
본문 먼저 실행
진입할 때는 검사하지 않으므로 본문이 반드시 한 번 실행됩니다.
-
식 검사
본문 실행 뒤 식을
bool로 문맥 변환합니다. -
true면 반복,false면 종료반복하면 다시 본문부터 실행하고, 끝나면 다음 문장으로 이어집니다.
최소 실행 횟수: 1회
continue는 가장 안쪽 반복문의 계속 지점으로 이동합니다. while은 앞의 조건 검사, do-while은 본문 뒤의 식 검사입니다. break는 가장 안쪽 반복문 또는 switch 하나를 끝냅니다.while 문: 조건이 참인 동안 반복
while 문은 주어진 조건이 참(true)인 동안 코드 블록을 반복적으로 실행합니다.
for 문과 달리 초기화와 상태 갱신을 조건식과 별도로 작성하므로, 반복 횟수보다는 조건에 중점을 둔 반복에 더 적합합니다.
// (초기화는 보통 while 문 바깥에서 수행)
while (조건) {
// 조건이 true인 동안 반복적으로 실행할 코드
// 조건이 끝나도록 상태를 바꾸거나 명시적인 탈출 경로를 둠
}조건: 매 반복이 시작되기 전에 평가됩니다. 이조건이true이면 반복 몸체가 실행되고,false이면while문이 종료됩니다.{ }(중괄호): 조건이 참일 때 실행될 코드 블록입니다.while문은for문과 달리 초기화와 증감 부분이 문법에 따로 포함되어 있지 않습니다. 끝나야 하는 반복이라면 조건이 언젠가false가 되도록 상태를 갱신하거나, 도달 가능한break·return같은 탈출 경로를 두어야 합니다.
while 문의 실행 흐름
조건 부분이 평가됩니다.
만약 조건이 true이면, while 문의 반복 몸체({ } 안의 코드)가 실행됩니다.
반복 몸체 실행이 끝나면, 다시 1번 단계로 돌아가 조건 부분을 평가합니다.
조건이 false가 될 때까지 2, 3번 과정을 반복합니다.
조건이 false가 되면 while 문이 종료되고 다음 코드가 실행됩니다.
#include <iostream>
int main() {
int i = 1; // 초기화
while (i <= 5) { // 조건
std::cout << i << " ";
i++; // 증감
}
std::cout << std::endl; // 출력: 1 2 3 4 5
return 0;
}#include <iostream>
#include <limits>
int main() {
int age;
std::cout << "나이를 입력하세요 (1-120): ";
// 정수 추출에 성공하고 값이 유효한 범위에 들어올 때까지 반복
while (!(std::cin >> age) || age < 1 || age > 120) {
if (std::cin.eof()) {
std::cerr << "입력이 종료되었습니다." << std::endl;
return 1;
}
// 비정수 입력으로 설정된 오류 상태를 풀고 현재 입력 줄을 버림
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "잘못된 나이입니다. 1에서 120 사이의 숫자를 다시 입력하세요: ";
}
std::cout << "입력하신 나이: " << age << std::endl; // 출력: 입력하신 나이: (사용자가 입력한 유효한 나이)
return 0;
}while (true)의 조건 자체는 항상 참이므로 조건 검사만으로는 루프가 끝나지 않습니다.
이 경우, break 문을 사용하여 특정 조건이 만족되면 루프를 강제로 종료할 수 있습니다.
이 명령 예제는 입력이 계속 성공하고 마지막에 exit을 입력하는 상황에서 break를 보여 줍니다. 입력 종료나 스트림 실패를 검사하지 않으므로 실제 입력 도구의 완성형으로 사용하지 않습니다. 아래 안전한 읽기 예제에서는 추출 실패 자체도 종료 조건으로 둡니다.
#include <iostream>
#include <string>
int main() {
std::string command;
std::cout << "명령을 입력하세요 ('exit'을 입력하면 종료):" << std::endl;
while (true) { // 무한 루프
std::cout << "> ";
std::cin >> command;
if (command == "hello") {
std::cout << "안녕하세요!" << std::endl;
} else if (command == "exit") {
std::cout << "프로그램을 종료합니다." << std::endl;
break; // 'exit'이 입력되면 루프 탈출
} else {
std::cout << "알 수 없는 명령입니다." << std::endl;
}
}
return 0;
}do-while 문: 최소 한 번은 실행되는 반복
do-while 문은 while 문과 유사하지만, 조건을 반복 몸체 실행 후에 평가한다는 점에서 차이가 있습니다.
이로 인해 do-while 문의 반복 몸체는 조건의 참/거짓 여부와 관계없이 최소 한 번은 반드시 실행됩니다.
do {
// 최소 한 번은 실행될 코드
// 끝나야 하는 반복이라면 상태 갱신 또는 명시적인 탈출 경로를 둠
} while (조건); // 조건 뒤에 세미콜론(;) 필수!do블록 안의 코드가 먼저 실행됩니다.- 그 후에
while괄호 안의조건이 평가됩니다. 조건이true이면do블록으로 돌아가 다시 실행하고,false이면 반복문이 종료됩니다.while (조건);뒤에 반드시 세미콜론(;)을 붙여야 합니다.
do-while 문의 실행 흐름
do 블록의 반복 몸체({ } 안의 코드)가 실행됩니다.
조건 부분이 평가됩니다.
만약 조건이 true이면, 1번 단계로 돌아가 반복 몸체를 다시 실행합니다.
조건이 false가 되면 do-while 문이 종료되고 다음 코드가 실행됩니다.
#include <iostream>
#include <limits>
int main() {
int num;
bool valid = false;
// do-while은 최소 한 번은 실행되므로, 첫 입력 유도 메시지를 루프 안에 넣기 편리
do {
std::cout << "0에서 9 사이의 숫자를 입력하세요: ";
if (std::cin >> num) {
valid = (num >= 0 && num <= 9);
} else {
if (std::cin.eof()) {
std::cerr << "입력이 종료되었습니다." << std::endl;
return 1;
}
std::cin.clear();
valid = false;
}
// 성공 여부와 관계없이 현재 입력 줄의 나머지를 버림
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} while (!valid); // 정수 추출에 성공하고 값이 유효할 때까지 반복
std::cout << "입력하신 숫자: " << num << std::endl;
return 0;
}만약 사용자가 첫 입력으로 5를 입력하면 valid가 true가 되고, 반복 조건 !valid가 false로 평가되어 루프가 종료됩니다.
나이 예제와 이 숫자 예제는 정수 추출과 값의 범위를 검사합니다. 줄 전체의 형식 검사는 아닙니다. 예를 들어 일반적인 십진 입력 5abc에서는 앞의 5를 읽는 데 성공하며, 여기서는 ignore가 나머지 abc를 버립니다. 나이 예제의 성공 경로는 줄의 나머지를 버리지도 않습니다. “추출 성공”, “값이 범위 안”, “줄 전체에 추가 문자가 없음”은 서로 다른 요구입니다.
사용자가 첫 입력으로 10을 입력하면 valid가 false이므로 !valid가 true로 평가되어 다시 입력을 요청하게 됩니다.
아래 메뉴도 정수 입력이 성공하며 마지막에 3을 선택한다고 가정합니다. choice를 읽은 뒤 성공 여부를 검사하지 않으므로 입력 실패 복구 예제가 아닙니다. 입력 실패를 다루는 프로그램에서는 값으로 분기하기 전에 추출 결과부터 검사합니다.
#include <iostream>
int main() {
int choice;
do {
std::cout << "\n--- 메뉴 ---" << std::endl;
std::cout << "1. 게임 시작" << std::endl;
std::cout << "2. 설정" << std::endl;
std::cout << "3. 종료" << std::endl;
std::cout << "선택: ";
std::cin >> choice;
switch (choice) {
case 1:
std::cout << "게임을 시작합니다!" << std::endl;
break;
case 2:
std::cout << "설정 화면으로 이동합니다." << std::endl;
break;
case 3:
std::cout << "게임을 종료합니다. 안녕히 가세요!" << std::endl;
break;
default:
std::cout << "잘못된 선택입니다. 다시 입력해주세요." << std::endl;
break;
}
} while (choice != 3); // choice가 3이 아니면 계속 반복
return 0;
}이 예시에서 메뉴는 최소 한 번은 출력되고 사용자의 입력을 받습니다.
사용자가 3을 입력하기 전까지 계속 메뉴가 반복됩니다.
for vs while vs do-while 비교
반복문을 고를 때는 반복 횟수가 정해져 있는지, 조건을 실행 전에 검사해야 하는지, 본문을 최소 한 번 실행해야 하는지를 먼저 가르면 됩니다.
| 특징 | for 문 | while 문 | do-while 문 |
|---|---|---|---|
| 초기화, 조건, 증감 | 한 줄에 명시적으로 표현 | 초기화는 외부, 증감은 내부에서 수동 관리 | 초기화는 외부, 증감은 내부에서 수동 관리 |
| 반복 실행 조건 | 루프 시작 전 조건 검사 | 루프 시작 전 조건 검사 | 루프 실행 후 조건 검사 |
| 최소 실행 횟수 | 0번 (조건이 처음부터 false이면) | 0번 (조건이 처음부터 false이면) | 1번 (조건과 관계없이) |
| 적합한 상황 | 반복 횟수가 명확할 때 (예: 배열 순회), 규칙적인 증감이 필요할 때 | 조건이 만족될 때까지 반복할 때 (예: 파일 읽기, 사용자 입력) | 최소 한 번은 실행해야 할 때 (예: 메뉴 시스템, 유효성 검사) |
| 주의사항 | 끝나야 한다면 조건·반복식·탈출 경로 확인 | 끝나야 한다면 상태 갱신 또는 도달 가능한 탈출 경로 확인 | while 뒤에 세미콜론(;) 필수, 상태 갱신 또는 도달 가능한 탈출 경로 확인 |
무한 루프 (Infinite Loops)
반복문의 조건이 항상 true로 평가되도록 작성되면 무한 루프(Infinite Loop)가 됩니다.
이는 프로그램이 끝나지 않고 계속 실행되는 상태를 만듭니다.
의도적인 경우가 아니면 버그로 이어집니다.
일반적인 무한 루프의 원인while문에서 조건을 변화시키는 코드가 없거나 잘못된 경우.for문에서 조건이 항상true인 경우 (예:for (;;)).
int counter = 0;
while (counter < 5) { // counter는 항상 0이므로 조건이 항상 true
std::cout << "반복 중..." << std::endl;
// counter++; // 이 증감 코드가 없어서 무한 루프!
}조건으로 끝내지 않는 반복은 while (true)나 for (;;)처럼 의도를 드러낼 수 있습니다. 내부에서 끝나야 하는 작업이라면 도달 가능한 break나 return 같은 별도 종료 경로가 필요하고, 계속 실행하도록 설계한 작업이라면 외부 중단 방식과 수명을 함께 정해야 합니다.
무한 루프는 조건식 자체보다 조건을 바꾸는 코드가 실제로 실행되는지에서 자주 갈립니다.
검사 시점, 갱신 위치, 탈출 경로를 함께 보면 while과 do-while의 차이도 더 선명해집니다.
종료 가능성은 모든 되돌아가는 경로에서 점검한다
skip=true를 명시한 한 반복에서 잘못된 continue 경로는 counter=0 유지, 수정 경로는 1로 증가한다. 독립된 두 프로그램의 진행 차이를 같은 프레임에서 비교한다.
PROGRESS · BACK EDGE · EXIT
모든 되돌아가는 경로에서 진행과 종료를 확인한다
조건식을 한 번 읽는 것만으로는 종료를 보장할 수 없습니다. 조건으로 되돌아가는 모든 경로에서 다음 검사 결과가 달라질 수 있는지 확인합니다.
잘못된 while은 continue에서 ++counter를 건너뛴다. 수정 버전에서는 작업을 건너뛰어도 ++counter를 수행한 뒤 조건으로 돌아간다. 두 프로그램은 독립 비교다.
관계도 해설과 예제 원자료
갱신을 건너뛸 수 있음
int counter = 0;
while (counter < 5) {
if (skip()) continue;
work();
++counter;
}
skip()이 계속 참이면 continue가 ++counter를 건너뛰어 조건은 계속 참입니다.
모든 정상 경로가 진행
int counter = 0;
while (counter < 5) {
if (!skip()) work();
++counter;
}
일반 경로와 작업을 건너뛰는 경로가 모두 갱신을 지난 뒤 다음 조건 검사로 돌아갑니다.
-
검사 시점을 표시한다
while과for는 본문 전,do-while은 본문 후에 검사합니다. 어떤 값이 다음 결과를 결정하는지 적습니다. -
되돌아가는 경로를 모두 추적한다
본문의 정상 끝뿐 아니라 조건문, 중첩 블록,
continue가 필요한 갱신을 우회하지 않는지 확인합니다. -
탈출 경로의 범위와 도달성을 확인한다
조건의
false는 반복을 끝냅니다. 이 장에서 다루는 문맥에서break는 자신을 둘러싼 반복문 또는switch문 가운데 가장 안쪽 문만 끝내므로, 중첩 구조에서는 어느 문을 대상으로 하는지 따로 봅니다.
while (true)나 for (;;)는 조건으로 종료하지 않겠다는 제어 형태입니다. 내부에서 끝나야 하는 작업이라면 도달 가능한 break, return 같은 별도 종료 계약을 명시하고, 계속 실행하도록 설계한 작업이라면 그 수명과 외부 중단 방식을 문서화합니다.이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 두 코드 사본 skip=true인 회차를 같은 counter=0에서 비교한다. |
|
|
| continue 경로 증가 위치가 제어 경로의 차이를 만든다. |
|
|
| 다음 검사 다음 반복 진입 상태를 나란히 읽는다. |
|
|
종료 가능성은 모든 되돌아가는 경로에서 점검한다
skip=true를 명시한 한 반복에서 잘못된 continue 경로는 counter=0 유지, 수정 경로는 1로 증가한다. 독립된 두 프로그램의 진행 차이를 같은 프레임에서 비교한다.
PROGRESS · BACK EDGE · EXIT
모든 되돌아가는 경로에서 진행과 종료를 확인한다
조건식을 한 번 읽는 것만으로는 종료를 보장할 수 없습니다. 조건으로 되돌아가는 모든 경로에서 다음 검사 결과가 달라질 수 있는지 확인합니다.
잘못된 while은 continue에서 ++counter를 건너뛴다. 수정 버전에서는 작업을 건너뛰어도 ++counter를 수행한 뒤 조건으로 돌아간다. 두 프로그램은 독립 비교다.
관계도 해설과 예제 원자료
갱신을 건너뛸 수 있음
int counter = 0;
while (counter < 5) {
if (skip()) continue;
work();
++counter;
}
skip()이 계속 참이면 continue가 ++counter를 건너뛰어 조건은 계속 참입니다.
모든 정상 경로가 진행
int counter = 0;
while (counter < 5) {
if (!skip()) work();
++counter;
}
일반 경로와 작업을 건너뛰는 경로가 모두 갱신을 지난 뒤 다음 조건 검사로 돌아갑니다.
-
검사 시점을 표시한다
while과for는 본문 전,do-while은 본문 후에 검사합니다. 어떤 값이 다음 결과를 결정하는지 적습니다. -
되돌아가는 경로를 모두 추적한다
본문의 정상 끝뿐 아니라 조건문, 중첩 블록,
continue가 필요한 갱신을 우회하지 않는지 확인합니다. -
탈출 경로의 범위와 도달성을 확인한다
조건의
false는 반복을 끝냅니다. 이 장에서 다루는 문맥에서break는 자신을 둘러싼 반복문 또는switch문 가운데 가장 안쪽 문만 끝내므로, 중첩 구조에서는 어느 문을 대상으로 하는지 따로 봅니다.
while (true)나 for (;;)는 조건으로 종료하지 않겠다는 제어 형태입니다. 내부에서 끝나야 하는 작업이라면 도달 가능한 break, return 같은 별도 종료 계약을 명시하고, 계속 실행하도록 설계한 작업이라면 그 수명과 외부 중단 방식을 문서화합니다.이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 두 코드 사본 skip=true인 회차를 같은 counter=0에서 비교한다. |
|
|
| continue 경로 증가 위치가 제어 경로의 차이를 만든다. |
|
|
| 다음 검사 다음 반복 진입 상태를 나란히 읽는다. |
|
|
예시
입력이 끝나도 종료되는 명령 읽기는 추출 결과를 조건에 넣을 수 있습니다. 아래 프로그램은 공백으로 구분한 hello와 exit 명령을 받으며, 한 줄 전체를 명령 하나로 읽는 방식은 아닙니다.
#include <iostream>
#include <string>
int main() {
std::string command;
while (std::cin >> command) {
if (command == "exit") {
break;
}
if (command == "hello") {
std::cout << "hello\n";
} else {
std::cout << "unknown\n";
}
}
std::cout << "done\n";
}hello exit을 입력하면 hello와 done을 한 줄씩 출력합니다. hello만 읽고 입력이 끝나도 다음 추출이 실패하여 hello와 done을 출력합니다. 입력 종료는 끝에 표시할 별도의 명령을 전송한 것이 아니라, 더 읽을 수 없다는 스트림 상태입니다. 문자열은 유지되어도 실패한 추출 뒤 본문에 다시 들어가지 않으므로 이전 명령을 재실행하지 않습니다.
검사 위치를 바꾸어 혼자 풀기
같은 초깃값 3에서 while (n < 3) { ++n; }와 do { ++n; } while (n < 3);의 본문 횟수와 마지막 n을 각각 적습니다. 초깃값을 0으로 바꾸면 두 반복의 결과가 같아지나요? 위 명령 프로그램에 hello를 읽히고 입력을 끝냈을 때 왜 clear()를 호출해 계속 기다리지 않는지도 설명해 보세요.
처음 검사와 정상 입력 종료 풀이
초깃값이 3이면 while은 본문을 0회 실행하고 최종값은 3입니다. do-while은 본문을 1회 실행하고 최종값은 4입니다. 초깃값이 0이면 둘 다 0·1·2 상태에서 본문을 총 3회 실행한 뒤 최종값이 3이 됩니다. 같은 결과가 나온 입력 하나로 두 구조가 항상 같다고 할 수는 없습니다. 명령 프로그램은 입력 종료를 작업 완료로 정했으므로 오류 상태를 무조건 풀어 재시도하지 않습니다.
예시 코드에서는 counter++가 조건을 바꾸는 갱신 지점입니다.
이 줄이 빠졌거나 continue 같은 분기가 갱신을 건너뛰어 조건이 계속 참으로 남는 상황은 초기 상태, 모든 되돌아가는 경로의 갱신 위치, 탈출 조건을 함께 확인하면 빠르게 찾을 수 있습니다.