Topic 3: 반복문 제어와 중첩 🎮
🎯 학습 목표
- break와 continue의 동작 원리를 이해할 수 있다
- 중첩 반복문의 구조와 활용법을 익힐 수 있다
- 복잡한 반복 로직을 효율적으로 구현할 수 있다
🛑 break문
반복문을 즉시 종료하고 빠져나가는 제어문입니다.
기본 사용법
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // i가 5일 때 반복문 종료
}
cout << i << " ";
}
cout << "\n반복문 종료!" << endl;
// 출력: 1 2 3 4 반복문 종료!
return 0;
}
실용적인 break 활용
#include <iostream>
using namespace std;
int main() {
int password;
int attempts = 0;
const int MAX_ATTEMPTS = 3;
while (attempts < MAX_ATTEMPTS) {
attempts++;
cout << attempts << "번째 시도 - 비밀번호 입력: ";
cin >> password;
if (password == 1234) {
cout << "✅ 로그인 성공!" << endl;
break; // 성공시 반복문 종료
} else {
cout << "❌ 잘못된 비밀번호입니다." << endl;
if (attempts < MAX_ATTEMPTS) {
cout << "남은 기회: " << (MAX_ATTEMPTS - attempts) << "번" << endl;
}
}
}
if (attempts == MAX_ATTEMPTS && password != 1234) {
cout << "🚫 계정이 잠겼습니다." << endl;
}
return 0;
}
⏭️ continue문
현재 반복을 건너뛰고 다음 반복으로 이동하는 제어문입니다.
기본 사용법
#include <iostream>
using namespace std;
int main() {
cout << "1부터 10까지 중 홀수만 출력:" << endl;
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 짝수면 다음 반복으로 건너뛰기
}
cout << i << " ";
}
cout << endl;
// 출력: 1 3 5 7 9
return 0;
}
continue 활용 예제
#include <iostream>
using namespace std;
int main() {
int sum = 0;
int count = 0;
cout << "양수만 입력받아 평균 계산 (0 입력시 종료)" << endl;
while (true) {
int number;
cout << "숫자 입력: ";
cin >> number;
if (number == 0) {
break; // 0이면 종료
}
if (number < 0) {
cout << "음수는 무시합니다." << endl;
continue; // 음수면 다음 반복으로
}
sum += number;
count++;
cout << "현재까지 평균: " << (double)sum / count << endl;
}
if (count > 0) {
cout << "최종 평균: " << (double)sum / count << endl;
} else {
cout << "입력된 양수가 없습니다." << endl;
}
return 0;
}
🔄 중첩 반복문
반복문 안에 또 다른 반복문을 넣는 구조입니다.
기본 구조와 예제
#include <iostream>
using namespace std;
int main() {
cout << "구구단 출력:" << endl;
for (int i = 2; i <= 9; i++) { // 외부 루프: 단수
cout << "\n" << i << "단:" << endl;
for (int j = 1; j <= 9; j++) { // 내부 루프: 곱하는 수
cout << i << " × " << j << " = " << (i * j) << endl;
}
}
return 0;
}
2차원 패턴 출력
#include <iostream>
using namespace std;
int main() {
// 1. 사각형 패턴
cout << "사각형 패턴:" << endl;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
cout << "* ";
}
cout << endl;
}
cout << "\n직각삼각형 패턴:" << endl;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= i; j++) {
cout << "* ";
}
cout << endl;
}
cout << "\n숫자 피라미드:" << endl;
for (int i = 1; i <= 5; i++) {
// 공백 출력
for (int j = 1; j <= 5 - i; j++) {
cout << " ";
}
// 숫자 출력
for (int j = 1; j <= i; j++) {
cout << j << " ";
}
cout << endl;
}
return 0;
}
🎯 중첩문에서의 break와 continue
라벨을 사용하지 않는 일반적인 방법
#include <iostream>
using namespace std;
int main() {
bool found = false;
cout << "특정 조건에서 중첩 루프 탈출:" << endl;
for (int i = 1; i <= 5 && !found; i++) {
for (int j = 1; j <= 5; j++) {
cout << "(" << i << ", " << j << ") ";
if (i == 3 && j == 3) {
found = true;
break; // 내부 루프만 탈출
}
}
cout << endl;
}
cout << "탐색 완료!" << endl;
return 0;
}
goto를 활용한 다중 루프 탈출 (권장하지 않음)
#include <iostream>
using namespace std;
int main() {
cout << "goto를 사용한 다중 루프 탈출 (비추천):" << endl;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
cout << "(" << i << ", " << j << ") ";
if (i == 3 && j == 3) {
goto exit_loops; // 모든 루프 탈출
}
}
cout << endl;
}
exit_loops:
cout << "\n모든 루프 탈출 완료!" << endl;
return 0;
}
🎮 실전 예제 - 간단한 패턴 찾기
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
cout << "숫자 패턴 찾기 예제" << endl;
// 3x3 격자에서 대각선 찾기
cout << "\n주 대각선:" << endl;
// 대각선에 별표 배치하기
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == j) { // 주 대각선
cout << "* ";
} else {
cout << ". ";
}
}
cout << endl;
}
cout << "\n반대 대각선:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i + j == 2) { // 반대 대각선
cout << "* ";
} else {
cout << ". ";
}
}
cout << endl;
}
return 0;
}
💡 활용 팁
1. 효율적인 중첩 루프 작성
// 좋은 예: 조건을 빨리 체크
for (int i = 0; i < n && !found; i++) {
for (int j = 0; j < m; j++) {
if (condition) {
found = true;
break;
}
}
}
// 나쁜 예: 불필요한 반복 계속
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (found) continue; // 비효율적!
// ... 작업
}
}
📚 퀴즈와 연습 문제
🧠 생각해보기: break vs continue
문제 1: 다음 코드의 출력 결과를 예상해보세요.
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0) {
continue;
}
if (i > 7) {
break;
}
cout << i << " ";
}
정답: 1 2 4 5 7
(3과 6은 continue로 건너뛰고, 8에서 break로 종료)
문제 2: 무한 루프에서 안전하게 탈출하는 방법은?
while (true) {
// 어떤 조건에서 탈출해야 할까요?
}
정답: 적절한 조건문과 break 사용, 또는 조건 변수 활용
🔧 고급 기법과 실전 팁
효율적인 중첩 루프 패턴
#include <iostream>
using namespace std;
int main() {
// 1. 플래그 변수를 활용한 다중 루프 탈출
bool found = false;
int target = 15;
cout << "2차원 배열에서 " << target << " 찾기:" << endl;
int arr[4][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17, 18, 19, 20}
};
for (int i = 0; i < 4 && !found; i++) {
for (int j = 0; j < 5 && !found; j++) {
cout << "검사 중: [" << i << "][" << j << "] = " << arr[i][j] << endl;
if (arr[i][j] == target) {
cout << "🎯 " << target << "을(를) [" << i << "][" << j << "]에서 발견!" << endl;
found = true;
}
}
}
if (!found) {
cout << "❌ " << target << "을(를) 찾을 수 없습니다." << endl;
}
return 0;
}
중첩 루프 최적화 기법
#include <iostream>
using namespace std;
int main() {
cout << "=== 최적화된 소수 판별 ===" << endl;
int limit = 100;
bool isPrime[101];
// 에라토스테네스의 체 알고리즘
for (int i = 0; i <= limit; i++) {
isPrime[i] = true;
}
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= limit; i++) {
if (isPrime[i]) {
// i의 배수들을 모두 소수가 아니라고 표시
for (int j = i * i; j <= limit; j += i) {
isPrime[j] = false;
}
}
}
cout << "1부터 " << limit << "까지의 소수:" << endl;
int count = 0;
for (int i = 2; i <= limit; i++) {
if (isPrime[i]) {
cout << i << " ";
count++;
if (count % 10 == 0) cout << endl;
}
}
cout << "\n총 " << count << "개의 소수를 찾았습니다." << endl;
return 0;
}
🎮 미니 프로젝트: 텍스트 RPG 전투 시스템
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
srand(time(0));
// 플레이어 상태
int playerHp = 100;
int playerAttack = 15;
string playerName;
// 몬스터 정보
string monsters[] = {"고블린", "오크", "트롤", "드래곤"};
int monsterHp[] = {30, 50, 80, 120};
int monsterAttack[] = {8, 12, 18, 25};
cout << "=== 텍스트 RPG 전투 시뮬레이터 ===" << endl;
cout << "용사의 이름을 입력하세요: ";
cin >> playerName;
cout << "\n" << playerName << " 용사님, 모험을 시작합니다!" << endl;
cout << "초기 체력: " << playerHp << " HP" << endl;
int stage = 0;
// 스테이지별 전투
while (stage < 4 && playerHp > 0) {
cout << "\n==== " << (stage + 1) << "단계: " << monsters[stage] << " 등장! ====" << endl;
int currentMonsterHp = monsterHp[stage];
int currentMonsterAttack = monsterAttack[stage];
cout << monsters[stage] << " - 체력: " << currentMonsterHp << " HP" << endl;
// 전투 루프
while (currentMonsterHp > 0 && playerHp > 0) {
cout << "\n--- 전투 중 ---" << endl;
cout << playerName << " HP: " << playerHp << endl;
cout << monsters[stage] << " HP: " << currentMonsterHp << endl;
cout << "\n1. 공격하기" << endl;
cout << "2. 방어하기" << endl;
cout << "3. 도망가기" << endl;
cout << "선택: ";
int choice;
cin >> choice;
switch (choice) {
case 1: { // 공격
int damage = playerAttack + (rand() % 11 - 5); // ±5 변동
if (damage < 1) damage = 1;
currentMonsterHp -= damage;
cout << "⚔️ " << playerName << "의 공격! " << damage << " 데미지!" << endl;
if (currentMonsterHp <= 0) {
cout << "🎉 " << monsters[stage] << "를 물리쳤습니다!" << endl;
playerHp += 20; // 승리 보상: 체력 회복
cout << "💖 체력이 20 회복되었습니다! 현재 HP: " << playerHp << endl;
break;
}
// 몬스터 반격
int monsterDamage = currentMonsterAttack + (rand() % 7 - 3);
if (monsterDamage < 1) monsterDamage = 1;
playerHp -= monsterDamage;
cout << "💥 " << monsters[stage] << "의 반격! " << monsterDamage << " 데미지!" << endl;
if (playerHp <= 0) {
cout << "💀 " << playerName << "이(가) 쓰러졌습니다..." << endl;
break;
}
break;
}
case 2: { // 방어
cout << "🛡️ 방어 자세를 취했습니다!" << endl;
int monsterDamage = (currentMonsterAttack + (rand() % 7 - 3)) / 2; // 데미지 반감
if (monsterDamage < 1) monsterDamage = 1;
playerHp -= monsterDamage;
cout << "💥 방어했지만 " << monsterDamage << " 데미지를 받았습니다!" << endl;
if (playerHp <= 0) {
cout << "💀 " << playerName << "이(가) 쓰러졌습니다..." << endl;
}
break;
}
case 3: { // 도망
if (rand() % 100 < 50) { // 50% 확률로 도망 성공
cout << "💨 성공적으로 도망쳤습니다!" << endl;
cout << "하지만 체력을 10 잃었습니다." << endl;
playerHp -= 10;
currentMonsterHp = 0; // 전투 종료
stage--; // 스테이지 진행 취소
} else {
cout << "❌ 도망에 실패했습니다!" << endl;
int monsterDamage = currentMonsterAttack + (rand() % 7 - 3);
if (monsterDamage < 1) monsterDamage = 1;
playerHp -= monsterDamage;
cout << "💥 " << monsters[stage] << "의 공격! " << monsterDamage << " 데미지!" << endl;
if (playerHp <= 0) {
cout << "💀 " << playerName << "이(가) 쓰러졌습니다..." << endl;
}
}
break;
}
default:
cout << "❌ 잘못된 선택입니다!" << endl;
continue; // 턴을 다시 진행
}
}
if (playerHp <= 0) {
break; // 게임 오버
}
stage++;
}
// 최종 결과
cout << "\n========= 게임 종료 =========" << endl;
if (playerHp > 0 && stage >= 4) {
cout << "🏆 축하합니다! 모든 몬스터를 물리치고 승리했습니다!" << endl;
cout << "최종 체력: " << playerHp << " HP" << endl;
cout << playerName << " 용사는 전설이 되었습니다!" << endl;
} else if (playerHp <= 0) {
cout << "💀 게임 오버..." << endl;
cout << (stage + 1) << "단계 " << monsters[stage] << "에게 패배했습니다." << endl;
cout << "다음에 더 강해져서 도전하세요!" << endl;
}
return 0;
}
💻 실전 디버깅: 흔한 실수들
실수 1: 중첩 루프에서 잘못된 break 사용
// ❌ 잘못된 예
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (i == 2 && j == 2) {
break; // 내부 루프만 빠져나감
}
cout << "(" << i << ", " << j << ") ";
}
}
// ✅ 올바른 해결 방법
bool shouldExit = false;
for (int i = 0; i < 5 && !shouldExit; i++) {
for (int j = 0; j < 5; j++) {
if (i == 2 && j == 2) {
shouldExit = true;
break;
}
cout << "(" << i << ", " << j << ") ";
}
}
실수 2: continue 위치 착각
// ❌ 잘못된 예
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
cout << i << "는 짝수입니다." << endl;
continue; // 이 아래 코드는 실행되지 않음
cout << "이 메시지는 출력되지 않습니다." << endl;
}
cout << i << "는 홀수입니다." << endl;
}
// ✅ 올바른 수정
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
cout << i << "는 짝수입니다." << endl;
} else {
cout << i << "는 홀수입니다." << endl;
}
// 모든 경우에 실행되어야 하는 코드는 여기에
cout << "처리 완료: " << i << endl;
}
🎯 핵심 정리
break와 continue 완벽 가이드
구분 | break | continue |
---|---|---|
작동 방식 | 반복문 완전 탈출 | 현재 반복만 건너뛰기 |
실행 위치 | break 이후 코드는 실행 안됨 | continue 이후 코드는 실행 안됨, 다음 반복으로 |
중첩에서 | 가장 안쪽 루프만 탈출 | 가장 안쪽 루프에서만 건너뛰기 |
용도 | 조건 만족시 반복 종료 | 특정 조건에서 처리 생략 |
중첩 반복문 설계 원칙
- 명확한 목적: 각 루프의 역할을 명확히 정의
- 효율성: 불필요한 반복 최소화 (조기 종료 조건 활용)
- 가독성: 적절한 들여쓰기와 변수명 사용
- 디버깅: 플래그 변수로 다중 루프 제어
실무 활용 패턴
- 2차원 데이터 처리: 행렬, 테이블, 게임 보드
- 알고리즘 구현: 정렬, 검색, 패턴 매칭
- 사용자 인터페이스: 메뉴 시스템, 게임 루프
- 데이터 검증: 조건부 처리, 예외 상황 관리
다음 토픽에서는 지금까지 배운 반복문 지식을 종합하여 실전 프로젝트를 만들어보겠습니다! 🚀
Last updated on