Lesson পড়তে ৮ মিনিট লাগবে

ইনপুট এবং আউটপুট স্ট্রিম (Input & Output with Streams)

স্ট্রিমগুলো (Streams) হলো অনেকটা কনভেয়র বেল্টগুলোর (conveyor belts) মতো — এক্ষেত্রে ডেটাগুলো শুধু একদিকে (one direction) প্রবাহিত হয়, আর আপনাকে শুধু এর ওপর আইটেমগুলো রাখতে (place) বা তুলে নিতে (pick) হয়

এখানকার এই কনভেয়র বেল্ট মডেল (The Conveyor Belt Model)

কিছুক্ষণের জন্য printf এবং scanf-এর কথা ভুলে যান। সি++ (C++) মূলত আপনার সামনে স্ট্রিম (streams) নামের একটি অত্যন্ত দারুণ বা বিউটিফুল (beautiful) আই/ও (I/O) অ্যাবস্ট্রাকশন (abstraction) নিয়ে এসেছে। কোনো কারখানার তৈরি একটি কনভেয়র বেল্টের (conveyor belt) কথা চিন্তা করুন:

  • cout — এটি হলো একটি আউটপুট বেল্ট (output belt)। আপনি <<-এর সাহায্যে এর ওপরে বিভিন্ন আইটেম রাখতে (place) পারেন, এবং এগুলো স্ক্রিনের দিকে গড়িয়ে পড়বে (roll out)।
  • cin — এটি হলো একটি ইনপুট বেল্ট (input belt)। এক্ষেত্রে কীবোর্ড (keyboard) থেকে বিভিন্ন আইটেম আসবে বা পৌঁছাবে, এবং আপনি >>-এর সাহায্যে সেগুলোকে তুলে (pick) নেবেন।
  • cerr — এটি হলো জরুরি বেল্ট (emergency belt)। এখানকার বিভিন্ন এরর বা ত্রুটির মেসেজগুলো (Error messages) মূলত এখানেই এসে থাকে — এগুলো মূলত আনবাফারড (unbuffered) হয়ে থাকে, যার ফলে এগুলো খুব দ্রুত বা তাৎক্ষণিকভাবে (immediately) স্ক্রিনে ভেসে ওঠে।

এই স্ট্রিমগুলোর (streams) প্রধান সৌন্দর্য বা বিউটি (beauty) হলো এদের টাইপ সেফটি (type safety)। যেমন printf("%d", x)-এর ক্ষেত্রে যদি আপনি কোনো ভুল ফরম্যাট স্পেসিফায়ার (format specifier) ব্যবহার করেন, তবে তা বিভিন্ন বাগের (bugs) কারণ হয়ে দাঁড়াবে, কিন্তু cout << x সব সময়ই x-এর টাইপ বা ধরনটি বুঝতে পারে এবং সেটিকে একদম সঠিকভাবে বা correctly প্রিন্ট (prints) করে।

cout-এর সাথে বেসিক আউটপুট (Basic Output)

#include <iostream>
using namespace std;
int main() {
string name = "Diana";
int age = 28;
double height = 5.7;
// << চিহ্নের মাধ্যমে একাধিক আইটেমকে বা multiple items চেইন বা চেইনিং (Chain) করুন
cout << "Name: " << name << endl;
cout << "Age: " << age << ", Height: " << height << endl;
// endl বনাম বা vs '\n'
cout << "This uses endl" << endl; // এটি মূলত বাফারটিকে (buffer) ফ্লাশ (flushes) করে
cout << "This uses \\n\n"; // এটি শুধুমাত্র একটি নিউলাইন (newline), কোনো ফ্লাশ নেই — তাই এটি সামান্য দ্রুত (slightly faster)
// এরর বা Error আউটপুট
cerr << "This is an error message!" << endl;
return 0;
}
Output
Name: Diana
Age: 28, Height: 5.7
This uses endl
This uses \n
This is an error message!

cin ব্যবহার করে ইনপুট পড়া বা Reading Input

cin >> মূলত একবারে শুধু একটি "টোকেন (token)"-ই পড়তে (reads) পারে — এটি যেকোনো হোয়াইটস্পেসে (whitespace) (যেমন স্পেস, ট্যাব, নিউলাইন) এসেই থেমে যায়। এর এই পদ্ধতিটি যেকোনো একক শব্দ বা নাম্বারের (numbers) ক্ষেত্রে দারুণ, কিন্তু আপনার যখন স্পেসসহ (with spaces) একটি সম্পূর্ণ লাইনের (full line) প্রয়োজন পড়বে তখন এটি ব্যর্থ (falls apart) হবে।

আর ঠিক এমন জায়গাতেই getline(cin, str)-এর ব্যবহারটি চলে আসে। এটি স্পেস (spaces) সহ নিউলাইন বা এন্টারের আগ পর্যন্ত সবকিছুই (everything until the newline) পড়তে (reads) পারে।

cin >> বনাম বা vs getline

#include <iostream>
#include <string>
using namespace std;
int main() {
// cin >> মূলত শুধু একটি টোকেন (token) পড়তে পারে (এটি হোয়াইটস্পেসে বা whitespace এসেই থেমে যায়)
int age;
cout << "Enter your age: ";
cin >> age;
cout << "You entered: " << age << endl;
// সমস্যা বা Problem: স্ট্রিংগুলোর ক্ষেত্রে cin >> মূলত প্রথম স্পেসটিতে (first space) এসেই আটকে যায়
string word;
cout << "Enter a word: ";
cin >> word;
cout << "Got: " << word << endl; // এটি শুধুমাত্র প্রথম শব্দটিই (first word) নিতে পারে!
cin.ignore(); // ⚠️ এর বেঁচে যাওয়া নিউলাইনটিকে (leftover newline) পরিষ্কার বা clear করুন!
// getline মূলত এর স্পেস (spaces) সহ পুরো লাইনটিকেই (entire line) পড়তে পারে
string fullName;
cout << "Enter your full name: ";
getline(cin, fullName);
cout << "Hello, " << fullName << "!" << endl;
return 0;
}
Output
Enter your age: 25
You entered: 25
Enter a word: hello
Got: hello
Enter your full name: John Doe
Hello, John Doe!
Note: cin >> মূলত যেকোনো হোয়াইটস্পেসে (whitespace) গিয়ে থেমে যায়। তাই সম্পূর্ণ লাইনের (full lines) ক্ষেত্রে getline(cin, str) ব্যবহার করুন। কিন্তু এই cin >> এবং getline-কে একসাথে ব্যবহার করাটা মূলত এক ধরনের সূক্ষ্ম বা স্ন্যিকি নিউলাইন বাগের (sneaky newline bug) জন্ম দিতে পারেcin >>-এর কাজ শেষ হলে বাফারে (buffer) একটি '\n' অবশিষ্ট (leftover) বা বেঁচে থাকে, আর এর পরপরই ঠিক ওই getline-টি এসে সেই বেঁচে যাওয়া অবশিষ্ট বা খালি লাইনটিকে (empty line) পড়ে নেয়। সমাধান বা Fix: এই ধরনের লুকিয়ে থাকা নিউলাইনটিকে (lurking newline) ফেলে (discard) দিতে এই দুইটির মাঝখানে মূলত cin.ignore()-কে কল (call) করুন।

iomanip ব্যবহার করে ফরম্যাটেড আউটপুট (Formatted Output)

আপনার কি কোনো টেবিলের কলামগুলোকে (columns) সাজানোর (line up) প্রয়োজন? ডেসিমাল (decimal) বা দশমিকের স্থানগুলোকে (places) নিয়ন্ত্রণ করার দরকার? কিংবা নাম্বারের (numbers) আগে শূন্য বসানোর (Pad with zeros) দরকার? এর এই <iomanip> হেডারটি (header) মূলত আপনার জন্য এই সমস্ত কাজেরই সমাধান নিয়ে এসেছে। এটি ম্যানিপুলেটরগুলো (manipulators) প্রদান করে থাকে — এগুলো হলো এমন কিছু বিশেষ অবজেক্ট (special objects), যা আপনি স্ট্রিমে ইনসার্ট (insert) করে তার পরবর্তী আইটেমটিকে কীভাবে ফরম্যাট বা সাজানো (formatted) হবে তা নির্ধারণ করে দিতে পারেন।

  • setw(n) — এটি মূলত পরবর্তী আউটপুট ফিল্ডের (output field) সর্বনিম্ন প্রস্থ বা প্রস্থের (minimum width) পরিমাণ নির্ধারণ করে দেয়
  • setprecision(n) — এটি মূলত ঠিক কতগুলো সংখ্যা (digits) দেখা যাবে তা নিয়ন্ত্রণ বা কন্ট্রোল করে
  • fixed — এটি মূলত ফিক্সড-পয়েন্ট নোটেশনগুলো (fixed-point notation) বা বিভিন্ন সাধারণ ডেসিমাল সংখ্যা (scientific নয়) প্রদর্শনে ব্যবহার করা হয়
  • left / right — এটি মূলত এর ফিল্ডের ওই প্রস্থের ভেতরেই এর অ্যালাইনমেন্ট (alignment) বা সজ্জা ঠিক করে দেয়
  • setfill(c) — এটি মূলত বিভিন্ন অতিরিক্ত স্পেসগুলোকে (spaces) খালি না রেখে নির্দিষ্ট কোনো অক্ষর বা ক্যারেক্টার c দিয়ে ওই জায়গাটিকে পূরণ (fill) করে দেয়

iomanip-এর সাহায্যে ফরম্যাটিং (Formatting)

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
// এর ডেসিমাল বা দশমিকের স্থানগুলোকে (places) নিয়ন্ত্রণ বা কন্ট্রোল (Controlling) করা
double pi = 3.141592653589793;
cout << "Default: " << pi << endl;
cout << "fixed(2): " << fixed << setprecision(2) << pi << endl;
cout << "fixed(6): " << fixed << setprecision(6) << pi << endl;
// সেটিকে পুনরায় ডিফল্ট বা default-এ রূপান্তর করা
cout << defaultfloat;
// setw-এর সাহায্যে টেবিলের অ্যালাইনমেন্ট বা Table alignment
cout << "\n--- Price List ---" << endl;
cout << left << setw(15) << "Item" << right << setw(8) << "Price" << endl;
cout << left << setw(15) << "Coffee" << right << setw(8) << fixed << setprecision(2) << 4.50 << endl;
cout << left << setw(15) << "Sandwich" << right << setw(8) << 8.99 << endl;
cout << left << setw(15) << "Cake" << right << setw(8) << 12.00 << endl;
// setfill-এর সাথে প্যাডিং বা Padding
cout << "\nOrder #" << setfill('0') << setw(5) << 42 << endl;
return 0;
}
Output
Default:    3.14159
fixed(2):   3.14
fixed(6):   3.141593

--- Price List ---
Item                Price
Coffee               4.50
Sandwich             8.99
Cake                12.00

Order #00042

স্ট্রিং স্ট্রিমগুলো (String Streams) — কোনো প্রকার I/O ছাড়াই স্ট্রিমগুলো (Streams Without I/O)

কখনো কখনো হয়তো আপনি কোনো একটি ফরম্যাট বা সাজানো স্ট্রিংকে (formatted string) প্রিন্ট না করেই (without) সেটি তৈরি বা নির্মাণ (build) করতে চান। এই <sstream>-এ থাকা stringstream-টি মূলত এমন একটি স্ট্রিম (stream) যা মেমোরিতে (memory) একটি string থেকে তার ডেটা পড়তে (reads) এবং সেটিতে তার ডেটা লিখতে (writes) পারে। এটিকে আপনি অনেকটা এমন একটি কনভেয়র বেল্টের (conveyor belt) মতো কল্পনা করতে পারেন, যা নিজেই নিজের ওপর ঘুরে আসে বা বৃত্ত তৈরি (loops back) করে — যেখানে আপনি এর ওপর বিভিন্ন জিনিস রাখেন (put things), এবং এরপর তার একত্র করা (assembled) ফলাফলটিকে একটি একক স্ট্রিং (single string) হিসেবে তুলে (take off) নেন।

বিভিন্ন ধরনের স্ট্রিং পার্সিং (parsing strings) বা যেকোনো জটিল আউটপুট (complex output) তৈরির ক্ষেত্রে এটি খুব অবিশ্বাস্যভাবে কার্যকর (incredibly handy) বা হ্যান্ডি।

স্ট্রিং স্ট্রিম (String Streams)

#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
// ostringstream-এর সাহায্যে একটি স্ট্রিং বিল্ড বা Building করা
ostringstream oss;
oss << "Score: " << 42 << "/" << 50 << " (" << 84.0 << "%)";
string report = oss.str();
cout << report << endl;
// istringstream-এর সাহায্যে একটি স্ট্রিং পার্স বা Parsing করা
string data = "Alice 95 Bob 87 Carol 92";
istringstream iss(data);
string name;
int score;
while (iss >> name >> score) {
cout << name << " scored " << score << endl;
}
return 0;
}
Output
Score: 42/50 (84%)
Alice scored 95
Bob scored 87
Carol scored 92

ইওএফ বা EOF (End Of File) পর্যন্ত পড়া বা Reading Until EOF

এখানকার একটি সাধারণ প্যাটার্ন (common pattern) হলো ইনপুটে যতক্ষণ পর্যন্ত না সবকিছু শেষ (nothing left) হয়ে যাচ্ছে, ততক্ষণ পর্যন্ত শুধু পড়তেই (reading) থাকা — এটি মূলত বিভিন্ন প্রতিযোগিতামূলক প্রোগ্রামিংগুলোতে (competitive programming) বা যেকোনো পাইপযুক্ত ফাইলগুলো (piped files) প্রসেস করার ক্ষেত্রে খুব দারুনভাবে কাজে আসে। cin >> variable-এর সাহায্যে আপনি চাইলেই এক্ষেত্রে একটি লুপ (loop) তৈরি করতে পারবেন — কারণ ইনপুটের ওই স্ট্রিমটি (stream) যখন শেষ বা ফুরিয়ে (exhausted) যায়, তখন এটি মূলত বিভিন্ন রেফারেন্সগুলোকে এমন একটি false রূপে রিটার্ন (returns) করে।

ইনপুট শেষ বা End of Input না হওয়া পর্যন্ত পড়া (Reading)

#include <iostream>
#include <string>
using namespace std;
int main() {
// ইওএফ বা EOF না হওয়া পর্যন্ত নাম্বার বা numbers পড়া (ম্যাক/লিনাক্সে বা Mac/Linux-এ Ctrl+D, এবং উইন্ডোজে বা Windows-এ Ctrl+Z)
int num;
int sum = 0;
int count = 0;
cout << "Enter numbers (Ctrl+D to stop):" << endl;
while (cin >> num) {
sum += num;
count++;
}
if (count > 0) {
cout << "Sum: " << sum << endl;
cout << "Average: " << (double)sum / count << endl;
}
return 0;
}
Output
Enter numbers (Ctrl+D to stop):
10 20 30 40
Sum: 100
Average: 25
চ্যালেঞ্জ

ছোট কুইজ

আপনি যদি "John Doe"-টিকে পড়ার জন্য (read) cin >> name ব্যবহার করেন, তবে আসলে কী ঘটবে?
Operators & ExpressionsConditionals