Skip to Content
💻 코리아IT아카데미 신촌 - 프로그래밍 학습 자료
C++ 프로그래밍Unit 14: 파일 입출력과 스트림Topic 3: 스트림 조작자와 포매팅

Topic 3: 스트림 조작자와 포매팅 - 아름다운 출력의 마법 🎨

🎯 학습 목표

  • 스트림 조작자의 개념과 필요성을 이해할 수 있다
  • setw, setprecision, setfill 등 주요 조작자를 활용할 수 있다
  • 진법 변환과 부호 표시 방법을 익힐 수 있다
  • 정렬과 채우기를 통한 깔끔한 출력을 만들 수 있다
  • 게임 UI처럼 전문적인 출력 화면을 구현할 수 있다

💄 화장품과 스트림 조작자

스트림 조작자 = 출력의 화장품 💄✨

기본 출력은 맨얼굴 같아요:

cout << "이름: " << "김철수" << endl; cout << "점수: " << 95 << endl; cout << "평균: " << 87.333333 << endl;

결과:

이름: 김철수 점수: 95 평균: 87.333333

스트림 조작자로 화장을 하면:

cout << setw(10) << left << "이름: " << "김철수" << endl; cout << setw(10) << left << "점수: " << setw(5) << right << 95 << endl; cout << setw(10) << left << "평균: " << fixed << setprecision(2) << 87.333333 << endl;

결과:

이름: 김철수 점수: 95 평균: 87.33

훨씬 깔끔하죠! 😍

📏 주요 스트림 조작자들

1. setw() - 출력 폭 설정 📐

#include <iostream> #include <iomanip> // 조작자 헤더 필수! using namespace std; int main() { cout << "기본 출력:" << endl; cout << 123 << endl; cout << 45 << endl; cout << 6789 << endl; cout << "\nsetw(6) 적용:" << endl; cout << setw(6) << 123 << endl; // 6자리로 우정렬 cout << setw(6) << 45 << endl; cout << setw(6) << 6789 << endl; return 0; }

출력 결과:

기본 출력: 123 45 6789 setw(6) 적용: 123 45 6789

2. left, right - 정렬 방향 ⬅️➡️

#include <iostream> #include <iomanip> using namespace std; int main() { cout << "좌정렬 (left):" << endl; cout << setw(10) << left << "Apple" << "|" << endl; cout << setw(10) << left << "Banana" << "|" << endl; cout << setw(10) << left << "Cherry" << "|" << endl; cout << "\n우정렬 (right):" << endl; cout << setw(10) << right << "Apple" << "|" << endl; cout << setw(10) << right << "Banana" << "|" << endl; cout << setw(10) << right << "Cherry" << "|" << endl; return 0; }

출력 결과:

좌정렬 (left): Apple | Banana | Cherry | 우정렬 (right): Apple| Banana| Cherry|

3. setfill() - 채우기 문자 설정 🎯

#include <iostream> #include <iomanip> using namespace std; int main() { cout << "기본 (공백으로 채우기):" << endl; cout << setw(10) << 123 << endl; cout << "\n별표로 채우기:" << endl; cout << setfill('*') << setw(10) << 123 << endl; cout << setw(10) << 456 << endl; cout << "\n0으로 채우기:" << endl; cout << setfill('0') << setw(8) << 123 << endl; cout << setw(8) << 45 << endl; return 0; }

출력 결과:

기본 (공백으로 채우기): 123 별표로 채우기: *******123 *******456 0으로 채우기: 00000123 00000045

4. setprecision() & fixed - 소수점 제어 🔢

#include <iostream> #include <iomanip> using namespace std; int main() { double pi = 3.141592653589793; double money = 1234.5; cout << "기본 출력:" << endl; cout << pi << endl; cout << money << endl; cout << "\nsetprecision(3):" << endl; cout << setprecision(3) << pi << endl; cout << money << endl; cout << "\nfixed + setprecision(2):" << endl; cout << fixed << setprecision(2) << pi << endl; cout << money << endl; return 0; }

출력 결과:

기본 출력: 3.14159 1234.5 setprecision(3): 3.14 1.23e+03 fixed + setprecision(2): 3.14 1234.50

🎮 실전 예제: 게임 스코어보드

아름다운 게임 스코어보드 만들기

#include <iostream> #include <iomanip> #include <vector> #include <string> using namespace std; struct Player { string name; int score; double accuracy; int level; }; void printScoreboard(const vector<Player>& players) { cout << "\n🏆 ========== 게임 스코어보드 ========== 🏆" << endl; // 헤더 출력 cout << setfill(' '); // 공백으로 채우기 cout << left; // 좌정렬 cout << setw(3) << "순위" << " | "; cout << setw(12) << "플레이어명" << " | "; cout << setw(8) << "점수" << " | "; cout << setw(8) << "정확도" << " | "; cout << setw(6) << "레벨" << endl; // 구분선 cout << setfill('-') << setw(50) << "" << endl; cout << setfill(' '); // 다시 공백으로 // 플레이어 정보 출력 for (size_t i = 0; i < players.size(); i++) { const Player& player = players[i]; // 순위 (우정렬, 0으로 채우기) cout << setfill('0') << setw(2) << right << (i + 1) << ". "; cout << setfill(' '); // 다시 공백으로 // 플레이어명 (좌정렬) cout << setw(12) << left << player.name << " | "; // 점수 (우정렬, 콤마 형식으로) cout << setw(8) << right << player.score << " | "; // 정확도 (고정소수점 2자리) cout << fixed << setprecision(1) << setw(6) << right << player.accuracy << "% | "; // 레벨 (우정렬) cout << setw(4) << right << player.level; // 등급 표시 if (i == 0) { cout << " 👑"; // 1등 } else if (i == 1) { cout << " 🥈"; // 2등 } else if (i == 2) { cout << " 🥉"; // 3등 } cout << endl; } cout << setfill('=') << setw(50) << "" << endl; cout << setfill(' '); // 원상복구 } int main() { // 게임 플레이어 데이터 vector<Player> players = { {"DragonSlayer", 98750, 94.3, 45}, {"MagicMaster", 87320, 91.7, 42}, {"SwordHero", 76890, 89.2, 38}, {"ArrowAce", 65430, 87.8, 35}, {"FireWizard", 54210, 85.1, 32} }; printScoreboard(players); // 추가 통계 정보 cout << "\n📊 ========== 게임 통계 ========== 📊" << endl; int totalScore = 0; double totalAccuracy = 0.0; for (const auto& player : players) { totalScore += player.score; totalAccuracy += player.accuracy; } cout << left; cout << setw(20) << "총 플레이어 수:" << players.size() << "명 👥" << endl; cout << setw(20) << "평균 점수:" << (totalScore / players.size()) << "점 🎯" << endl; cout << setw(20) << "평균 정확도:" << fixed << setprecision(1) << (totalAccuracy / players.size()) << "% 🎪" << endl; return 0; }

실행 결과:

🏆 ========== 게임 스코어보드 ========== 🏆 순위 | 플레이어명 | 점수 | 정확도 | 레벨 -------------------------------------------------- 01. DragonSlayer | 98750 | 94.3% | 45 👑 02. MagicMaster | 87320 | 91.7% | 42 🥈 03. SwordHero | 76890 | 89.2% | 38 🥉 04. ArrowAce | 65430 | 87.8% | 35 05. FireWizard | 54210 | 85.1% | 32 ================================================== 📊 ========== 게임 통계 ========== 📊 총 플레이어 수: 5명 👥 평균 점수: 76520점 🎯 평균 정확도: 89.6% 🎪

🔢 진법과 부호 표시

다양한 진법으로 출력하기

#include <iostream> #include <iomanip> using namespace std; int main() { int number = 255; cout << "숫자 " << number << "을(를) 다양한 진법으로:" << endl; cout << "================================" << endl; // 10진법 (기본) cout << "10진법: " << dec << number << endl; // 16진법 cout << "16진법: " << hex << number << " (소문자)" << endl; cout << "16진법: " << uppercase << hex << number << " (대문자)" << endl; // 8진법 cout << "8진법: " << oct << number << endl; // 다시 10진법으로 복구 cout << nouppercase << dec; // 부호 표시 cout << "\n부호 표시:" << endl; cout << "양수: " << showpos << 123 << endl; cout << "음수: " << -456 << endl; cout << "0: " << 0 << endl; // 부호 표시 끄기 cout << noshowpos; return 0; }

출력 결과:

숫자 255을(를) 다양한 진법으로: ================================ 10진법: 255 16진법: ff (소문자) 16진법: FF (대문자) 8진법: 377 부호 표시: 양수: +123 음수: -456 0: +0

🎪 고급 포매팅: 게임 상점 시스템

전문적인 게임 상점 인터페이스

#include <iostream> #include <iomanip> #include <vector> #include <string> using namespace std; struct Item { int id; string name; int price; string rarity; int stock; }; class GameShop { private: vector<Item> items; int playerGold; public: GameShop(int gold) : playerGold(gold) { // 상점 아이템 초기화 items = { {1, "강철검", 1500, "일반", 5}, {2, "마법지팡이", 2500, "희귀", 3}, {3, "용의갑옷", 5000, "전설", 1}, {4, "체력포션", 100, "일반", 20}, {5, "마나포션", 150, "일반", 15}, {6, "불꽃반지", 3500, "희귀", 2}, {7, "순간이동서", 800, "일반", 8} }; } void displayShop() { cout << "\n🏪 ========== 모험가 상점 ========== 🏪" << endl; cout << "💰 보유 골드: " << setfill(',') << playerGold << "G" << endl; cout << setfill(' '); // 원상복구 cout << endl; // 헤더 cout << left; cout << setw(4) << "ID" << " | "; cout << setw(15) << "아이템명" << " | "; cout << setw(8) << "가격" << " | "; cout << setw(8) << "등급" << " | "; cout << setw(6) << "재고" << " | "; cout << "상태" << endl; // 구분선 cout << setfill('─') << setw(60) << "" << endl; cout << setfill(' '); // 아이템 목록 for (const auto& item : items) { // ID cout << setw(3) << right << item.id << ". "; // 아이템명 (좌정렬) cout << setw(15) << left << item.name << " | "; // 가격 (우정렬, 콤마) cout << setw(6) << right << item.price << "G | "; // 등급 (가운데 정렬처럼 보이게) string rarity = item.rarity; cout << setw(8) << left; if (rarity == "전설") { cout << "💎" + rarity; } else if (rarity == "희귀") { cout << "💙" + rarity; } else { cout << "⚪" + rarity; } cout << " | "; // 재고 cout << setw(4) << right << item.stock << "개 | "; // 구매 가능 여부 if (item.stock == 0) { cout << "❌ 품절"; } else if (playerGold >= item.price) { cout << "✅ 구매가능"; } else { cout << "💸 골드부족"; } cout << endl; } cout << setfill('═') << setw(60) << "" << endl; cout << setfill(' '); } void displayReceipt(int itemId, int quantity) { auto it = find_if(items.begin(), items.end(), [itemId](const Item& item) { return item.id == itemId; }); if (it == items.end()) return; int totalPrice = it->price * quantity; cout << "\n🧾 ========== 구매 영수증 ========== 🧾" << endl; cout << left; cout << setw(20) << "아이템:" << it->name << endl; cout << setw(20) << "단가:" << it->price << "G" << endl; cout << setw(20) << "수량:" << quantity << "개" << endl; cout << setfill('-') << setw(35) << "" << endl; cout << setfill(' '); cout << setw(20) << "총 금액:" << totalPrice << "G 💰" << endl; cout << setw(20) << "보유 골드:" << playerGold << "G" << endl; cout << setw(20) << "거래 후 금액:" << (playerGold - totalPrice) << "G" << endl; cout << setfill('═') << setw(35) << "" << endl; cout << setfill(' '); cout << "✨ 구매해 주셔서 감사합니다! ✨" << endl; } }; int main() { GameShop shop(7500); // 7500골드로 시작 shop.displayShop(); cout << "\n구매 시뮬레이션:" << endl; shop.displayReceipt(2, 1); // 마법지팡이 1개 구매 return 0; }

🗂️ 파일 출력에 포매팅 적용

예쁜 리포트 파일 생성

#include <iostream> #include <fstream> #include <iomanip> #include <vector> using namespace std; struct GameStats { string playerName; int totalGames; int wins; int losses; double winRate; int highestScore; }; void generateReport(const vector<GameStats>& stats) { ofstream report("game_report.txt"); if (!report.is_open()) { cout << "❌ 리포트 파일을 생성할 수 없습니다!" << endl; return; } // 파일에 포매팅된 리포트 작성 report << "🎮 ========== 게임 통계 리포트 ========== 🎮" << endl; report << "생성일: 2024년 3월 15일" << endl; report << "====================================" << endl << endl; // 헤더 report << left; report << setw(12) << "플레이어" << " | "; report << setw(8) << "총경기" << " | "; report << setw(6) << "승리" << " | "; report << setw(6) << "패배" << " | "; report << setw(8) << "승률" << " | "; report << setw(10) << "최고점수" << endl; report << setfill('-') << setw(60) << "" << endl; report << setfill(' '); // 데이터 출력 for (const auto& stat : stats) { report << setw(12) << left << stat.playerName << " | "; report << setw(8) << right << stat.totalGames << " | "; report << setw(6) << right << stat.wins << " | "; report << setw(6) << right << stat.losses << " | "; report << fixed << setprecision(1) << setw(6) << right << stat.winRate << "% | "; report << setw(10) << right << stat.highestScore << endl; } report << setfill('=') << setw(60) << "" << endl; report << setfill(' '); report.close(); cout << "✅ 게임 리포트가 'game_report.txt'에 저장되었습니다!" << endl; } int main() { vector<GameStats> playerStats = { {"김철수", 50, 35, 15, 70.0, 98500}, {"이영희", 45, 30, 15, 66.7, 87200}, {"박민수", 60, 45, 15, 75.0, 95300}, {"최지영", 40, 22, 18, 55.0, 76800} }; generateReport(playerStats); return 0; }

💡 핵심 정리

  • 스트림 조작자: 출력 형식을 제어하는 도구들
  • #include <iomanip>: 조작자 사용을 위한 필수 헤더
  • setw(): 출력 폭 설정 (한 번만 적용됨)
  • left/right: 정렬 방향 설정 (계속 유지됨)
  • setfill(): 빈 공간을 채울 문자 설정
  • setprecision(): 소수점 자릿수 설정
  • fixed: 고정소수점 형식으로 출력
  • dec/hex/oct: 진법 설정
  • showpos/noshowpos: 양수 부호 표시 여부

✅ 실습 체크리스트

🚀 다음 시간 예고

다음 시간에는 문자열 스트림과 변환에 대해 알아볼 거예요!

  • stringstream을 활용한 문자열 처리
  • 문자열과 숫자 간의 자유로운 변환
  • 문자열 파싱과 데이터 추출 기법
  • 게임 명령어 처리 시스템 구현하기

“아름다운 출력으로 사용자 경험을 향상시키세요! 🎨✨”

Last updated on