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
67892. 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
000000454. 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