Skip to Content
💻 코리아IT아카데미 신촌 - 프로그래밍 학습 자료
C++ 프로그래밍Unit 4: 반복문Topic 3: 반복문 제어와 중첩

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 완벽 가이드

구분breakcontinue
작동 방식반복문 완전 탈출현재 반복만 건너뛰기
실행 위치break 이후 코드는 실행 안됨continue 이후 코드는 실행 안됨, 다음 반복으로
중첩에서가장 안쪽 루프만 탈출가장 안쪽 루프에서만 건너뛰기
용도조건 만족시 반복 종료특정 조건에서 처리 생략

중첩 반복문 설계 원칙

  1. 명확한 목적: 각 루프의 역할을 명확히 정의
  2. 효율성: 불필요한 반복 최소화 (조기 종료 조건 활용)
  3. 가독성: 적절한 들여쓰기와 변수명 사용
  4. 디버깅: 플래그 변수로 다중 루프 제어

실무 활용 패턴

  • 2차원 데이터 처리: 행렬, 테이블, 게임 보드
  • 알고리즘 구현: 정렬, 검색, 패턴 매칭
  • 사용자 인터페이스: 메뉴 시스템, 게임 루프
  • 데이터 검증: 조건부 처리, 예외 상황 관리

다음 토픽에서는 지금까지 배운 반복문 지식을 종합하여 실전 프로젝트를 만들어보겠습니다! 🚀

Last updated on