Giao diện
📥 Input/Output với iostream
C++ sử dụng streams (luồng) để xử lý I/O. Stream là abstraction mạnh mẽ cho phép đọc/ghi từ console, files, và strings với cùng syntax.
Basic Output: std::cout
cpp
#include <iostream>
int main() {
// Basic output
std::cout << "Hello, PENALGO!" << std::endl;
// Chaining << operator
int age = 25;
std::string name = "HPN";
std::cout << "Name: " << name << ", Age: " << age << std::endl;
// endl vs '\n'
std::cout << "Line 1" << std::endl; // Flush buffer
std::cout << "Line 2\n"; // No flush, faster
std::cout << "Line 3" << '\n'; // Same as above
return 0;
}💡 std::endl vs '\n'
std::endl= '\n' + flush buffer → chậm hơn'\n'= chỉ newline → nhanh hơn cho output nhiều dòng- Dùng
std::endlkhi cần đảm bảo output xuất hiện ngay (debugging)
Basic Input: std::cin
cpp
#include <iostream>
#include <string>
int main() {
// Input số
int number;
std::cout << "Nhập một số: ";
std::cin >> number;
std::cout << "Bạn nhập: " << number << std::endl;
// Input nhiều giá trị
int a, b;
std::cout << "Nhập 2 số (cách nhau bởi space): ";
std::cin >> a >> b;
std::cout << "Tổng: " << (a + b) << std::endl;
// ⚠️ Input string với std::cin chỉ đọc đến space
std::string word;
std::cout << "Nhập một từ: ";
std::cin >> word; // Chỉ nhận từ đầu tiên!
std::cout << "Từ: " << word << std::endl;
return 0;
}std::getline() — Đọc cả dòng
cpp
#include <iostream>
#include <string>
int main() {
std::string fullName;
std::cout << "Nhập họ tên đầy đủ: ";
std::getline(std::cin, fullName); // Đọc cả dòng, bao gồm spaces
std::cout << "Xin chào, " << fullName << "!" << std::endl;
return 0;
}⚠️ Mixing std::cin >> và std::getline
cpp
#include <iostream>
#include <string>
int main() {
int age;
std::string name;
std::cout << "Nhập tuổi: ";
std::cin >> age;
// ❌ Bug! getline sẽ đọc newline còn sót lại từ cin >>
std::cout << "Nhập tên: ";
std::getline(std::cin, name); // name sẽ rỗng!
std::cout << "Name: '" << name << "'" << std::endl; // ''
return 0;
}Fix:
cpp
std::cin >> age;
std::cin.ignore(); // Bỏ qua newline còn sót
std::getline(std::cin, name);
// Hoặc:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');Output Formatting với <iomanip>
cpp
#include <iostream>
#include <iomanip> // Cho setw, setprecision, etc.
int main() {
// === setw: Set width ===
std::cout << "=== setw demo ===" << std::endl;
std::cout << std::setw(10) << 42 << std::endl; // " 42"
std::cout << std::setw(10) << std::left << 42 << std::endl; // "42 "
std::cout << std::setw(10) << std::right << 42 << std::endl; // " 42"
// === setfill: Fill character ===
std::cout << "\n=== setfill demo ===" << std::endl;
std::cout << std::setfill('0') << std::setw(5) << 42 << std::endl; // "00042"
std::cout << std::setfill('-') << std::setw(10) << "Hi" << std::endl; // "--------Hi"
std::cout << std::setfill(' '); // Reset
// === Floating-point precision ===
double pi = 3.141592653589793;
std::cout << "\n=== precision demo ===" << std::endl;
std::cout << "Default: " << pi << std::endl; // 3.14159
std::cout << "setprecision(3): " << std::setprecision(3) << pi << std::endl; // 3.14
std::cout << "setprecision(10): " << std::setprecision(10) << pi << std::endl; // 3.141592654
// === fixed vs scientific ===
double bigNum = 1234567.89;
std::cout << "\n=== fixed/scientific demo ===" << std::endl;
std::cout << std::setprecision(2);
std::cout << "Default: " << bigNum << std::endl; // 1.2e+06
std::cout << "Fixed: " << std::fixed << bigNum << std::endl; // 1234567.89
std::cout << "Scientific: " << std::scientific << bigNum << std::endl; // 1.23e+06
return 0;
}Table Formatting Example
cpp
#include <iostream>
#include <iomanip>
#include <string>
struct Product {
std::string name;
double price;
int quantity;
};
int main() {
Product products[] = {
{"Laptop", 25000000, 5},
{"Mouse", 500000, 20},
{"Keyboard", 1500000, 15},
{"Monitor", 8000000, 3}
};
// Print table header
std::cout << std::left;
std::cout << std::setw(15) << "Product"
<< std::setw(15) << "Price (VND)"
<< std::setw(10) << "Qty"
<< std::setw(18) << "Total" << std::endl;
std::cout << std::setfill('-') << std::setw(58) << "" << std::endl;
std::cout << std::setfill(' ');
// Print rows
double grandTotal = 0;
for (const auto& p : products) {
double total = p.price * p.quantity;
grandTotal += total;
std::cout << std::left << std::setw(15) << p.name
<< std::right << std::setw(15) << std::fixed << std::setprecision(0) << p.price
<< std::setw(10) << p.quantity
<< std::setw(18) << total << std::endl;
}
std::cout << std::setfill('=') << std::setw(58) << "" << std::endl;
std::cout << std::setfill(' ');
std::cout << std::left << std::setw(40) << "Grand Total:"
<< std::right << std::setw(18) << grandTotal << std::endl;
return 0;
}Output:
Product Price (VND) Qty Total
----------------------------------------------------------
Laptop 25000000 5 125000000
Mouse 500000 20 10000000
Keyboard 1500000 15 22500000
Monitor 8000000 3 24000000
==========================================================
Grand Total: 181500000std::cerr và std::clog
cpp
#include <iostream>
int main() {
// std::cout — Standard output (buffered)
std::cout << "Normal output" << std::endl;
// std::cerr — Standard error (unbuffered, flushed immediately)
std::cerr << "Error message!" << std::endl;
// std::clog — Logging (buffered, goes to stderr)
std::clog << "Log entry" << std::endl;
// Trong terminal, bạn có thể redirect riêng:
// ./program > output.txt 2> errors.txt
return 0;
}Input Validation
cpp
#include <iostream>
#include <limits>
int main() {
int number;
while (true) {
std::cout << "Nhập một số nguyên: ";
if (std::cin >> number) {
break; // Input hợp lệ
} else {
std::cout << "❌ Input không hợp lệ! Vui lòng nhập số." << std::endl;
// Clear error flag
std::cin.clear();
// Discard invalid input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
std::cout << "✅ Bạn nhập: " << number << std::endl;
return 0;
}📚 Tổng kết
| Concept | Usage |
|---|---|
std::cout | Output chuẩn (buffered) |
std::cin | Input chuẩn (đọc đến whitespace) |
std::cerr | Error output (unbuffered) |
std::getline() | Đọc cả dòng bao gồm spaces |
std::setw() | Set column width |
std::setprecision() | Decimal precision |
std::fixed | Fixed-point notation |
cin.ignore() | Skip characters in input buffer |
➡️ Tiếp theo
Bạn đã nắm vững I/O! Tiếp theo: Exercises — 3 bài tập thực hành để củng cố kiến thức.
🧠 Quiz
Câu 1: Sự khác biệt giữa std::endl và '\n' là gì?
- [ ] A) Không có sự khác biệt
- [x] B)
std::endlflush buffer còn'\n'thì không - [ ] C)
'\n'flush buffer cònstd::endlthì không - [ ] D)
std::endlchỉ dùng được vớistd::cout
💡 Giải thích:
std::endlthực hiện hai việc: xuống dòng ('\n') + flush buffer (ép dữ liệu trong buffer ghi ra output ngay).'\n'chỉ xuống dòng mà không flush → nhanh hơn khi output nhiều dòng.
Câu 2: Đoạn code sau có vấn đề gì?
cpp
int age;
std::string name;
std::cout << "Nhập tuổi: ";
std::cin >> age;
std::cout << "Nhập tên: ";
std::getline(std::cin, name);- [ ] A) Không có vấn đề
- [x] B)
getlineđọc ký tự'\n'còn sót trong buffer từcin >> - [ ] C) Không thể dùng
cinvàgetlinecùng nhau - [ ] D)
getlinekhông hoạt động vớistd::string
💡 Giải thích: Sau
cin >> age, ký tự'\n'(Enter) vẫn còn trong input buffer. Khi gọigetline, nó đọc ngay'\n'đó và trả về chuỗi rỗng. Cách fix: thêmstd::cin.ignore()trướcgetline.
Câu 3: Để in số thực với đúng 2 chữ số thập phân, cần dùng gì?
- [ ] A)
std::cout << std::setw(2) << num; - [x] B)
std::cout << std::fixed << std::setprecision(2) << num; - [ ] C)
std::cout << std::precision(2) << num; - [ ] D)
std::cout << std::round(num, 2);
💡 Giải thích: Cần kết hợp
std::fixed(chế độ fixed-point) vớistd::setprecision(2)(2 chữ số thập phân).std::setwchỉ set chiều rộng cột, không liên quan đến decimal places.