এই পর্বে যা শিখবেন
- প্রথম C++ প্রোগ্রামের প্রতিটি শব্দ ও চিহ্ন কী কাজ করে, আর compiler ও কম্পিউটার কখন কী করে
std::cout,<<-এর চেইন,'\n'বনামstd::endl, আরstd::cerrকেন আলাদা- namespace কেন দরকার,
using namespace std;কখন ঠিক আর কখন বিপদ - C++23-এর
std::print/std::println— কখন কোন স্টাইল বেছে নেবেন main-এর ফেরত দেওয়া সংখ্যা (exit code) কে পড়ে, আর প্রথম দিনের error দেখে কারণ চেনা
১ · ছোট প্রোগ্রাম, কিন্তু প্রতিটি লাইনের একটা দায়িত্ব আছে
পর্ব ০৩-এ আপনি দেখেছেন, g++ কীভাবে কোডকে চালানো যায় এমন প্রোগ্রামে বদলায়। এবার সেই কোডটিই খুলে দেখার পালা। নিচের ছয় লাইনের প্রোগ্রামটি প্রায় সব C++ বইয়ের প্রথম প্রোগ্রাম:
#include <iostream>
int main() {
std::cout << "Hello, Dhaka!" << '\n';
return 0;
}অনেকে এটিকে “মুখস্থ করার জিনিস” মনে করেন — প্রতিটি প্রোগ্রামের শুরুতে লিখে দিতে হয়, ব্যস। কিন্তু এই মনোভাবই পরে বিপদ ডেকে আনে। কারণ এই ছয় লাইনের ভেতরেই লুকিয়ে আছে C++-এর চারটি বড় ধারণা: header থেকে যন্ত্র আনা, প্রোগ্রামের শুরুর জায়গা, stream দিয়ে লেখা পাঠানো, আর অপারেটিং সিস্টেমকে ফলাফল জানানো। এগুলো বুঝলে সামনের পর্বগুলোর অনেক error নিজেই ধরতে পারবেন।
অফিসে একটি আবেদনপত্রের কথা ভাবুন। ওপরে “বরাবর” — কাকে লিখছেন। তারপর বিষয়। তারপর মূল লেখা। শেষে নাম আর স্বাক্ষর। প্রতিটি অংশের নির্দিষ্ট কাজ আছে; স্বাক্ষর বাদ দিলে আবেদন গ্রহণ হয় না, বিষয় বাদ দিলে কেউ বোঝে না কী চাইছেন। C++ প্রোগ্রামও এমন একটি আনুষ্ঠানিক কাগজ — পাঠক এখানে compiler আর অপারেটিং সিস্টেম। তারা ঠিক জানে কোন অংশ কোথায় থাকবে।
এক নজরে প্রতিটি লাইনের দায়িত্ব:
| লাইন | কে পড়ে | কী কাজ |
|---|---|---|
#include <iostream> | Preprocessor | iostream header-এর ঘোষণাগুলো এনে বসায় — std::cout কী, তা compiler এখান থেকেই জানে |
int main() { | Compiler, পরে OS | প্রোগ্রামের শুরুর জায়গা; int মানে শেষে একটি পূর্ণসংখ্যা ফেরত দেবে |
std::cout << … ; | Compiler, পরে CPU | লেখাটি standard output-এ (সাধারণত স্ক্রিনে) পাঠায় |
return 0; | OS | “কাজ ঠিকঠাক শেষ” — এই বার্তা অপারেটিং সিস্টেমকে দেয় |
} | Compiler | main-এর শরীর এখানে শেষ |
এবার একই প্রোগ্রাম আরেকটু বড় করে ধাপে ধাপে চালাই। প্রতিটি ধাপে দেখুন — সবুজ লাইনটি নিয়ে কে কাজ করছে, আর স্ক্রিনে কী আসছে। “পরে” চাপুন:
1#include <iostream>23int main() {4 // my first C++ program5 std::cout << "Hello, Dhaka!" << '\n';6 std::cout << "Learning C++" << '\n';7 return 0;8}
| কে কাজ করছে | |
| exit code |
#include <iostream>— যন্ত্র আনা। Preprocessor compile শুরুর আগেইiostreamheader-এর লেখা এনে এই জায়গায় বসিয়ে দেয়। এখানেই ঘোষণা করা আছেstd::cout,std::cinআর<<-এর নিয়ম। খেয়াল করুন, C-র মতো.hনেই — standard C++ header-এর নামে এক্সটেনশন থাকে না।int main()— শুরুর দরজা। Compiler এখানেmainনামের একটি ফাংশন দেখে। প্রোগ্রাম চালু করলে অপারেটিং সিস্টেম প্রথমে কিছু প্রস্তুতির কোড (startup code) চালায়, তারপর ঠিক এই ফাংশনটি ডাকে। এজন্য একে বলে entry point. পুরো প্রোগ্রামেmainথাকতে হবে ঠিক একটি।- Comment — শুধু মানুষের জন্য।
//থেকে লাইনের শেষ পর্যন্ত লেখাটি comment. Compiler একে পুরোপুরি বাদ দেয়; চূড়ান্ত প্রোগ্রামে এর কোনো চিহ্ন থাকে না। এটি ভবিষ্যতের পাঠকের (প্রায়ই আপনি নিজেই) জন্য নোট। - প্রথম লেখা স্ক্রিনে। এবার প্রোগ্রাম সত্যিই চলছে — CPU নির্দেশ পালন করছে।
"Hello, Dhaka!"আর তারপর'\n'(নতুন লাইনের অক্ষর)std::cout-এ ঢুকল, স্ক্রিনে এলো প্রথম লাইন। লাইনের শেষের;বলে দেয় এই statement এখানে শেষ। - দ্বিতীয় লেখা। একই কাজ আবার। Statement-গুলো ওপর থেকে নিচে, একটার পর একটা চলে — এই সরল নিয়মটিই সব প্রোগ্রামের ভিত্তি। পর্ব ০৮-এ দেখবেন, if আর লুপ দিয়ে এই ক্রম কীভাবে বদলানো যায়।
return 0;— রিপোর্ট জমা।mainশেষ হচ্ছে, আর অপারেটিং সিস্টেমকে একটি সংখ্যা ফেরত দিচ্ছে: 0, মানে “কোনো সমস্যা হয়নি”. এই সংখ্যাকে বলে exit code. অংশ ৬-এ এর গুরুত্ব দেখবেন।}— শেষ।main-এর block বন্ধ হলো, প্রোগ্রাম শেষ। Terminal-এecho $?লিখলে (Linux/Mac) শেষ প্রোগ্রামের exit code দেখা যায় — এখানে 0. সব মিলিয়ে: preprocessor আর compiler কাজ করেছে আগে, CPU আর OS করেছে চালানোর সময়।
একটি C++ প্রোগ্রামের দুটি জীবন। Compile-এর সময় preprocessor ও compiler কোড পড়ে, ভুল ধরে, machine code বানায় — তখন কিছুই স্ক্রিনে ছাপা হয় না। চালানোর সময় OS প্রোগ্রাম চালু করে main ডাকে, আর CPU একটার পর একটা statement চালায়। কোন error কোন জীবনে আসছে, সেটা চেনাই debugging-এর প্রথম ধাপ।
“Hello, World” প্রোগ্রামের প্রচলন শুরু হয় Brian Kernighan-এর লেখা থেকে — ১৯৭৮ সালের বিখ্যাত বই The C Programming Language-এ এটি প্রথম উদাহরণ ছিল, আর তার আগে Bell Labs-এর একটি টিউটোরিয়ালেও এর ব্যবহার দেখা যায়। ১৯৮৫ সালে Bjarne Stroustrup তাঁর The C++ Programming Language বইয়ে একই প্রোগ্রাম লেখেন, কিন্তু printf-এর বদলে cout << দিয়ে। সেই থেকে << চিহ্নটিই C++-এর পরিচিত চেহারা।
২ · C++-এর ব্যাকরণ — statement, block আর comment
বাংলায় বাক্য শেষ হয় দাঁড়ি দিয়ে। C++-এ প্রতিটি নির্দেশ — statement — শেষ হয় সেমিকোলন ; দিয়ে। Compiler লাইন ভাঙা দেখে না; সে দেখে ;. তাই চাইলে একটি statement কয়েক লাইনে ভেঙে লেখা যায়, আবার এক লাইনে দুটি statement-ও লেখা যায়। পড়ার সুবিধার জন্য আমরা সাধারণত এক লাইনে একটি রাখি।
Block — কোঁকড়া বন্ধনীর ঘর
{ আর }-এর মাঝের অংশকে বলে block. একটি block কয়েকটি statement-কে একসাথে বেঁধে রাখে — যেমন main-এর শরীর। প্রতিটি {-এর একটি জোড়া } থাকতেই হবে। ভেতরের লাইনগুলো চার ঘর সরিয়ে (indent) লেখা নিয়ম নয়, অভ্যাস — compiler এটি দেখে না, কিন্তু মানুষ এতে block-এর সীমা এক নজরে বোঝে।
Comment-এর দুই রূপ
// এক লাইনের comment: লাইনের শেষ পর্যন্ত
/* কয়েক লাইনের comment:
এখানে যত লাইন খুশি লেখা যায় */
std::cout << "Hi" << '\n'; // কোডের পাশেও লেখা যায়ভালো comment বলে কেন, কী নয়। // print Hi লেখার দরকার নেই, কোড দেখেই তা বোঝা যায়। কিন্তু // bKash API needs amount in poisha, not taka — এমন comment পরে কাউকে বড় ভুল থেকে বাঁচাতে পারে। Comment-এর ভেতরে বাংলা লেখা যায়; কোডের বাকি অংশে নয়।
বড় হাতের আর ছোট হাতের অক্ষর আলাদা
C++ case-sensitive: main, Main আর MAIN তিনটি সম্পূর্ণ আলাদা নাম। OS খোঁজে ঠিক main. ভুল করে Main লিখলে compiler আপত্তি করে না (নতুন একটি ফাংশন হিসেবে নেয়), কিন্তু শেষে linker বলবে main খুঁজে পাওয়া যায়নি। অংশ ৭-এ এই error হাতেনাতে দেখবেন।
Statement, ;, block, comment, main আর return 0-এর ধারণা C-র মতোই। নতুন হলো <stdio.h>-এর বদলে <iostream>, printf-এর বদলে টাইপ-নিরাপদ std::cout <<, আর namespace. আরেকটি ছোট পার্থক্য: C++-এ int main() মানেই “কোনো আর্গুমেন্ট নেই”, তাই C-র মতো (void) লেখার দরকার নেই। C-র দিকটি গভীরে দেখতে চাইলে পড়ুন C কোর্সের পর্ব ০৪ — প্রথম প্রোগ্রাম।
৩ · Stream — std::cout একটি পাইপ
C++-এ স্ক্রিনে লেখা মানে কোনো ফাংশনকে ডাকা নয়, বরং একটি stream-এ লেখা ঢালা। Stream কথাটির মানে স্রোত — অক্ষরের একটানা স্রোত, যা একদিকে ঢোকে, অন্যদিকে বের হয়। std::cout (পড়ুন “সি-আউট”, character output) এমন একটি পাইপ, যার অন্য মাথা আপনার স্ক্রিনে (আরও ঠিকভাবে বললে, standard output-এ) খোলে।
চা-দোকানের সামনে একটি পাইপের কথা ভাবুন, যার অন্য মাথা কারখানার ভেতরে। পাইপে আপনি একটার পর একটা জিনিস ঢোকাচ্ছেন — প্রথমে একটি কথা, তারপর একটি সংখ্যা, তারপর “নতুন লাইন” লেখা একটি চিরকুট। ওপাশে সেগুলো ঠিক একই ক্রমে বের হয়। << চিহ্নটি দেখতেও তীরের মতো: ডান দিকের জিনিস বাঁ দিকের পাইপে ঢুকছে।
<<-কে বলে insertion operator (“ঢোকানোর অপারেটর”). এর সবচেয়ে সুন্দর দিক হলো, এটি নিজেই বুঝে নেয় কী ঢোকানো হচ্ছে — লেখা, পূর্ণসংখ্যা, দশমিক সংখ্যা বা একটি অক্ষর। printf-এর মতো %d বা %s বলে দিতে হয় না, তাই ভুল format দেওয়ার ঝুঁকিও নেই। এটি সম্ভব হয়েছে operator overloading-এর কারণে — প্রতিটি টাইপের জন্য <<-এর আলাদা সংস্করণ আছে, আর compiler ঠিকটি বেছে নেয়। পর্ব ২৩-এ নিজের টাইপের জন্য << বানানোও শিখবেন।
চেইন — কেন একটার পর একটা << লেখা যায়
std::cout << "Dhaka " << 2026 << '\n'; — এক লাইনে তিনটি জিনিস। এটি কাজ করে একটি ছোট কৌশলে: প্রতিটি << কাজ শেষে সেই একই stream ফেরত দেয়। নিচে দেখুন compiler লাইনটি আসলে কীভাবে ভাঙে:
std::cout << "Dhaka " << 2026 << '\n'; ((std::cout << "Dhaka ") << 2026) << '\n'; // << বাঁ দিক থেকে জোড়া বাঁধে (left-to-right)
((std::cout << "Dhaka ") << 2026) << '\n'; ↓ ছাপে "Dhaka ", ফেরত দেয় std::cout (std::cout << 2026) << '\n';
(std::cout << 2026) << '\n'; ↓ সংখ্যাকে '2' '0' '2' '6' অক্ষরে বদলে ছাপে std::cout << '\n';
std::cout << '\n'; ↓ নতুন লাইন ছাপে, ফেরত দেয় std::cout std::cout;
std::cout; // ফল আর কোথাও লাগবে না — ; এখানে statement শেষ // প্রতিটি << আসলে একটি ফাংশন ডাকা: operator<<(operator<<(operator<<(std::cout, "Dhaka "), 2026), '\n');
- দলে ভাগ।
<<বাঁ দিক থেকে জোড়া বাঁধে। তাই compiler লাইনটিকে এভাবে দেখে: প্রথমেstd::cout << "Dhaka ", তার ফলের সাথে<< 2026, তার ফলের সাথে<< '\n'. এখনো কিছু ছাপা হয়নি। - প্রথম জোড়া। ভেতরের বন্ধনী আগে। লেখার জন্য বানানো
<<চলল:"Dhaka "stream-এ ঢুকল। তারপর সেটি ফেরত দিল সেই একইstd::cout(আসলে তার একটি reference — পর্ব ১০-এ বিস্তারিত)। ফলে বাকি অংশটা হয়ে গেলstd::cout << 2026 << '\n'. - সংখ্যা। এবার
int-এর জন্য বানানো আরেকটি<<বেছে নেওয়া হলো। সংখ্যা 2026 মেমরিতে থাকে বাইনারিতে; স্ক্রিনে দেখাতে হলে তাকে চারটি অক্ষরে বদলাতে হয় — এই কাজটি stream নিজেই করে। আবার ফেরত এলোstd::cout. - নতুন লাইন।
'\n'একটি অক্ষর (একক কোটে, তাইchar). এটি ঢুকতেই স্ক্রিনের কার্সর পরের লাইনে চলে গেল।"\n"(জোড়া কোটে) লিখলেও একই ফল — সেটি এক অক্ষরের একটি string. - ফল ফেলে দেওয়া। সব শেষে হাতে থাকে শুধু
std::cout, যা দিয়ে আর কিছু করার নেই —;statement শেষ করে। নিচের লাইনটি দেখায়, প্রতিটি<<আসলে একটি ফাংশন ডাকা। যদি<<কিছু ফেরত না দিত, দ্বিতীয়<<-এর বাঁ পাশে কিছুই থাকত না — চেইন অসম্ভব হতো।
চেইনে হিসাব থাকলে সাবধান। std::cout << 5 + 3; ঠিক আছে — + আগে হয়, ছাপে 8. কিন্তু <<-এর চেয়ে দুর্বল অপারেটর (যেমন &, ==, ?:) থাকলে compiler ভুল দলে ভাগ করে। নিরাপদ অভ্যাস: হিসাবকে বন্ধনীতে রাখুন — std::cout << (a == b);. অপারেটরের অগ্রাধিকার পর্ব ০৬-এ।
'\n' নাকি std::endl?
দুটোই নতুন লাইন দেয়, কিন্তু std::endl একটা বাড়তি কাজ করে: flush. ব্যাপারটি বুঝতে buffer চিনতে হবে। স্ক্রিনে বা ফাইলে প্রতিটি অক্ষর আলাদা করে পাঠানো ব্যয়বহুল — প্রতিবার অপারেটিং সিস্টেমকে ডাকতে হয়। তাই stream লেখাগুলো প্রথমে একটি অস্থায়ী জায়গায় (buffer) জমায়, জমা হলে একবারে পাঠায়।
লোকাল বাসের কথা ভাবুন। প্রতিটি যাত্রী উঠলেই বাস ছেড়ে দিলে রাস্তায় হাজারটা বাস লাগত। তাই বাস কিছু যাত্রী জমিয়ে তারপর ছাড়ে — এটাই buffer. std::endl মানে প্রতিটি যাত্রী ওঠার পরই চালককে বলা “এখনই ছাড়ুন!” — একজন-দুজনের বেলায় সমস্যা নেই, কিন্তু দশ লাখ লাইন ছাপানোর লুপে এটি প্রোগ্রামকে অনেকগুণ ধীর করে দিতে পারে।
তাহলে std::endl কখন? যখন এই মুহূর্তেই লেখাটা বাইরে যাওয়া জরুরি — যেমন লম্বা কাজের আগে “Processing…” দেখাতে, অথবা ক্র্যাশের আশঙ্কা থাকলে লগ লিখতে। সাধারণ ক্ষেত্রে '\n' লিখুন। আরেকটি সুখবর: std::cin দিয়ে কিছু পড়ার আগে std::cout নিজে থেকেই flush হয় (দুটি stream “বাঁধা” থাকে), তাই প্রশ্ন ছাপিয়ে ইনপুট চাইলে প্রশ্নটা ঠিকই আগে দেখা যায়।
চারটি standard stream
| Stream | দিক | কাজ | Buffer |
|---|---|---|---|
std::cout | বাইরে | সাধারণ ফলাফল | আছে |
std::cerr | বাইরে | error মেসেজ | নেই — সঙ্গে সঙ্গে যায় |
std::clog | বাইরে | লগ বা তথ্য | আছে |
std::cin | ভেতরে | কিবোর্ড থেকে পড়া (>>) | আছে |
std::cerr আলাদা কেন? ধরুন ./report > result.txt লিখে ফলাফল ফাইলে পাঠালেন। তখন std::cout-এর সব লেখা ফাইলে যাবে, কিন্তু std::cerr-এর লেখা তবুও স্ক্রিনে আসবে — ফলে error মেসেজ ফাইলের ডেটার সাথে মিশে যায় না, আর আপনি সাথে সাথে দেখতে পান। ক্র্যাশের ঠিক আগে লেখা error হারিয়ে না যাওয়ার জন্যই এর buffer নেই।
৪ · আধুনিক বিকল্প — C++23-এর std::print আর std::println
<<-এর চেইন টাইপ-নিরাপদ, কিন্তু লম্বা বাক্যে একটু খটমটে। "Rafi got " << marks << " out of " << total << '\n' — বাক্যটি টুকরো টুকরো হয়ে গেছে, এক নজরে পুরোটা পড়া যায় না। এই সমস্যা মেটাতে C++20-এ এসেছে std::format, আর C++23 থেকে এসেছে std::print ও std::println (header <print>). এরা ফাঁকা ঘর {} — placeholder — ব্যবহার করে; পরের মানগুলো ক্রমানুসারে সেই ঘরে বসে। println শেষে নিজেই নতুন লাইন যোগ করে।
#include <iostream>
#include <print>
int main() {
// Style 1: stream -- pieces go into std::cout with <<
std::cout << "Hello, Dhaka!" << '\n';
std::cout << "Cups of tea: " << 3 << '\n';
// Style 2 (C++23): {} placeholders are filled in order
std::println("{} + {} = {}", 20, 26, 20 + 26);
std::println("Hello again, {}!", "Chattogram");
return 0; // 0 tells the operating system: all OK
}প্রথম দুই লাইন পুরোনো, পরিচিত stream স্টাইল। পরের দুই লাইনে std::println: প্রথম আর্গুমেন্টটি format string, তার ভেতরের প্রতিটি {} পরের মানগুলো দিয়ে ক্রমানুসারে ভরে যায় — 20 + 26-এর হিসাব আগে হয়, তারপর 46 বসে। ভালো দিক: format string ভুল হলে (যেমন ঘর তিনটি কিন্তু মান দুটি) compiler compile-এর সময়েই ধরে ফেলে, চালানোর সময় অদ্ভুত ফল দেয় না। নিজের কম্পিউটারে চালাতে g++ -std=c++23 লাগবে, আর <print> header আছে GCC 14 ও তার নতুন version-এ।
কখন কোন স্টাইল?
std::cout <<
সব compiler-এ, সব পুরোনো কোডে চলে। ফাইল-stream আর string-stream-এর সাথে একই নিয়ম। নানা পরীক্ষার প্রশ্ন, পুরোনো বই আর বেশিরভাগ কনটেস্ট সমাধানে এটিই দেখবেন — তাই পড়তে জানতেই হবে।
সবখানে চলে, পড়তে জানা বাধ্যতামূলক std::println("{}")
পুরো বাক্য এক জায়গায় দেখা যায়, অনুবাদ করা সহজ, সংখ্যার format (দশমিকের পর কত ঘর) ঠিক করা সহজ। নতুন প্রজেক্টে, যেখানে compiler C++23 সমর্থন করে, এটি বেছে নিতে পারেন।
নতুন কোডে, C++23 compiler লাগেএই কোর্সে দুটোই ব্যবহার হবে। ইনপুট-আউটপুটের পুরো খুঁটিনাটি — দশমিক ঘর, প্রস্থ, বাঁ-ডানে সাজানো, ভুল ইনপুট সামলানো — আসবে পর্ব ০৭-এ (ইনপুট-আউটপুট — cin, cout, format আর print).
৫ · Namespace — ক্লাসে দুজন রহিম থাকলে
ধরুন একটি ক্লাসে দুজন ছাত্রের নাম রহিম। শিক্ষক “রহিম!” ডাকলে দুজনই দাঁড়িয়ে যায়। সমাধান? পদবি দিয়ে ডাকা — “রহিম চৌধুরী” আর “রহিম হোসেন”. প্রোগ্রামিংয়েও ঠিক এই সমস্যা হয়। বড় প্রোগ্রামে কয়েকটি library একসাথে ব্যবহার হয়; দুটি library-তেই print বা count নামে কিছু থাকা খুব স্বাভাবিক। তখন compiler বুঝতে পারে না কোনটা চাইছেন।
C++-এর সমাধান namespace — নামের একটি পরিবার বা পদবি। Standard library-র সব নাম (cout, cin, string, vector, sort, count…) থাকে std নামের namespace-এ। std::cout মানে “std পরিবারের cout”. মাঝের :: চিহ্নটিকে বলে scope resolution operator — বাংলায় বলা যায় “-এর ভেতরের”. নিচে দেখুন সংঘাত কীভাবে ঘটে আর কীভাবে মেটে:
// এক দল লিখেছে বাংলা অ্যাপের জন্য void print() { std::cout << "Dhonnobad\n"; } // আরেক দল লিখেছে ইংরেজি অ্যাপের জন্য void print() { std::cout << "Thank you\n"; } int main() { print(); }
thanks.cpp:4:6: error: redefinition of 'void print()'
thanks.cpp:2:6: note: 'void print()' previously defined here
namespace bangla { void print() { std::cout << "Dhonnobad\n"; } } namespace english { void print() { std::cout << "Thank you\n"; } }
int main() {
bangla::print(); // Dhonnobad
english::print(); // Thank you
}
using namespace bangla;
using namespace english;
int main() { print(); }
thanks.cpp:9:19: error: call of overloaded 'print()' is ambiguous
candidate 1: 'void bangla::print()'
candidate 2: 'void english::print()'
- দুই দল, একই নাম। দুটি আলাদা দল নিজেদের কোডে
printনামে ফাংশন লিখেছে — দুজনের কাছেই নামটি একদম যুক্তিসংগত। সমস্যা হয় যখন দুটি কোড একটি প্রোগ্রামে এসে মেলে। - সংঘাত। Compiler বলছে
redefinition— “এই নাম তো আগেই একবার সংজ্ঞায়িত হয়েছে!” একই জায়গায় একই নামে দুটি ফাংশন থাকতে পারে না। namespace আসার আগে লোকে এড়াত নামের আগে উপসর্গ লাগিয়ে —bn_print,en_print— যা লম্বা আর ঝামেলার। - পদবি দেওয়া। প্রতিটি ফাংশনকে নিজের
namespace-এর ঘরে রাখা হলো। এখন তাদের পুরো নাম আলাদা:bangla::printআরenglish::print. দুটি দল একে অপরের কথা না জেনেও নিশ্চিন্তে কাজ করতে পারে। - পুরো নাম দিয়ে ডাকা।
::দিয়ে বলে দিলেন কোন পরিবারের কোন সদস্য। কোনো দ্বিধা নেই, compile হয়, দুটি লাইনই ছাপা হয়।std::coutঠিক এই নিয়মেই কাজ করে —stdহলো standard library-র পদবি। - শর্টকাটের বিপদ।
using namespaceমানে “এই পরিবারের সবাইকে পদবি ছাড়াই ডাকব।” দুটি পরিবার একসাথে খুলে দিলে আবার সেই পুরোনো দ্বিধা — দুজন রহিম, কাকে ডাকছেন? Compiler বলেambiguous.using namespace std;-এর ঝুঁকিও ঠিক এটাই, নিচে দেখুন।
using namespace std; — সুবিধা না ঝুঁকি?
std:: বারবার লিখতে ক্লান্ত লাগে, তাই অনেক টিউটোরিয়াল শুরুতেই লেখে using namespace std;. এতে std-এর সব নাম — কয়েক হাজার — আপনার প্রোগ্রামের সাধারণ জায়গায় ঢুকে পড়ে। নিজের ভ্যারিয়েবলের নাম count রাখলেন? std::count নামে একটি algorithm-ও আছে:
using namespace std;
int count = 0;
int main() { count++; }
error: reference to 'count' is ambiguous
আজ হয়তো চলছে, কিন্তু standard library-তে প্রতিটি নতুন version-এ নতুন নাম যোগ হয়। আজকের নিরীহ কোড কাল নতুন compiler-এ ভেঙে যেতে পারে। তাই সিদ্ধান্তের নিয়মটি এমন:
| পদ্ধতি | কী করে | কোথায় ঠিক |
|---|---|---|
std::cout (পুরো নাম) | প্রতিবার পদবিসহ ডাকা | সবখানে — পেশাদার কোডের ডিফল্ট |
using std::cout; | শুধু একটি নির্দিষ্ট নাম পদবি ছাড়া | .cpp ফাইলে, বা ফাংশনের ভেতরে — মাঝামাঝি পথ |
using namespace std; | std-এর সব নাম একবারে খুলে দেয় | কনটেস্ট, ছোট পরীক্ষামূলক কোড। header ফাইলে কখনো নয় |
Header-এ কেন একেবারেই নয়? কারণ header যত ফাইল #include করে, সবার ভেতরে সেই using ছড়িয়ে পড়ে — এমন মানুষের কোডেও, যারা জানেই না। পর্ব ১১-এ (namespace আর header) নিজের namespace আর header দিয়ে বড় প্রোগ্রাম সাজানো শিখবেন।
নিজের namespace, সাথে প্রথম ইনপুট
এবার সব একসাথে। নিচের প্রোগ্রাম আপনার নাম পড়ে দুই ভাষায় শুভেচ্ছা জানায়। দুটি নতুন জিনিস আছে, শুধু চিনে রাখুন: std::string — লেখা রাখার একটি বাক্স (পর্ব ১৪-এ বিস্তারিত), আর std::cin >> name — কিবোর্ড থেকে একটি শব্দ পড়ে name-এ রাখে। খেয়াল করুন তীরের দিক: >> মানে stream থেকে বেরিয়ে ভ্যারিয়েবলে যাচ্ছে। এখানে ইনপুট হিসেবে Rafi দেওয়া আছে:
#include <iostream>
#include <string>
namespace bangla {
void greet(std::string name) { std::cout << "Shubho shokal, " << name << "!\n"; }
}
namespace english {
void greet(std::string name) { std::cout << "Good morning, " << name << "!\n"; }
}
int main() {
std::string name;
std::cout << "Your name: ";
std::cin >> name; // reads one word
std::cout << '\n';
bangla::greet(name);
english::greet(name);
} // no return here: only main gets an automatic "return 0"দুটি namespace-এ একই নামের greet ফাংশন, কিন্তু কোনো সংঘাত নেই — পুরো নাম আলাদা। std::cin >> name প্রথম ফাঁকা জায়গা (space বা Enter) পর্যন্ত পড়ে; “Rafi Ahmed” দিলে name-এ যেত শুধু “Rafi”. পুরো লাইন পড়ার উপায় পর্ব ০৭-এ। আর শেষের comment-টি খেয়াল করুন: main-এর শেষে return না লিখলে C++ ধরে নেয় return 0; — এই সুবিধা শুধু main-এর, অন্য কোনো ফাংশনের নয়।
৬ · main-এর ফেরত দেওয়া সংখ্যা — কে পড়ে, কেন জরুরি
int main()-এর int একটি প্রতিশ্রুতি: “শেষে একটি পূর্ণসংখ্যা ফেরত দেব।” এই সংখ্যা আপনার প্রোগ্রামের ভেতরে কেউ ব্যবহার করে না — এটি যায় অপারেটিং সিস্টেমের কাছে, আর সেখান থেকে যে প্রোগ্রাম আপনার প্রোগ্রামকে চালিয়েছে তার কাছে (সাধারণত terminal-এর shell). নিয়মটি সহজ: 0 মানে সফল, অন্য যেকোনো সংখ্যা মানে কোনো সমস্যা. <cstdlib> header-এ এর দুটি নামও আছে: EXIT_SUCCESS আর EXIT_FAILURE.
কুরিয়ার সার্ভিসের ডেলিভারি ম্যানের কথা ভাবুন। পার্সেল দিয়ে এসে অফিসে শুধু একটি কোড লেখেন — 0 মানে “পৌঁছে গেছে”, 1 মানে “ঠিকানা পাইনি”, 2 মানে “প্রাপক ফেরত দিয়েছেন”. অফিস সেই কোড দেখেই ঠিক করে পরের কাজ কী। Exit code-ও তেমনি — ছোট একটি সংখ্যা, কিন্তু অন্য প্রোগ্রাম এর ওপর ভরসা করে সিদ্ধান্ত নেয়।
Compile, চালানো, আর exit code দেখা
পর্ব ০৩-এর প্রতিদিনের কমান্ড দিয়েই compile করুন, তারপর চালিয়ে exit code দেখুন:
g++ -std=c++23 -Wall -Wextra -g hello.cpp -o hello
./hello
echo $?g++ -std=c++23 -Wall -Wextra -g hello.cpp -o hello.exe
.\hello.exe
echo $LASTEXITCODE # PowerShell-এ
echo %errorlevel% # পুরোনো Command Prompt-এএই সংখ্যা সত্যিকারের কাজে লাগে। Shell-এ ./build && ./test লিখলে দ্বিতীয়টি চলে কেবল প্রথমটি 0 ফেরত দিলে। পর্ব ০৩-এ দেখা collect2: error: ld returned 1 exit status মেসেজটি মনে আছে? সেটি ঠিক এই জিনিস — linker 1 ফেরত দিয়েছে, তাই g++ বুঝেছে কাজ ব্যর্থ। GitHub Actions-এর মতো CI সিস্টেমও টেস্ট প্রোগ্রামের exit code দেখেই সবুজ বা লাল দাগ দেয়।
void main() C++-এ বৈধ নয়। পুরোনো Turbo C++-এর দিনের অনেক বই আর নোটে এটি দেখবেন, সাথে #include <iostream.h> আর conio.h. আধুনিক g++ সরাসরি error দেয়: error: '::main' must return 'int'. আরেকটি বিষয়: Linux-এ exit code-এর শুধু নিচের ৮ bit পৌঁছায়, তাই মান থাকে 0 থেকে 255-এর মধ্যে — return 256; করলে shell দেখবে 0, অর্থাৎ “সফল”! ব্যর্থতা জানাতে ছোট ধনাত্মক সংখ্যা (যেমন 1) ব্যবহার করুন।
আরেকটি রূপও চিনে রাখুন: int main(int argc, char* argv[]). এভাবে লিখলে প্রোগ্রাম চালানোর সময় কমান্ডের সাথে দেওয়া শব্দগুলো (command-line argument) হাতে পাওয়া যায় — যেমন ./greet Rafi. শুরুতে আমাদের শুধু খালি বন্ধনীর রূপটিই লাগবে।
- C++ প্রোগ্রাম কোথা থেকে চলা শুরু করে? —
mainফাংশন থেকে; পুরো প্রোগ্রামে এটি ঠিক একটি থাকে, আর ফেরত দেয়int. std::endlআর'\n'-এর পার্থক্য কী? — দুটোই নতুন লাইন দেয়;std::endlসাথে buffer flush-ও করে, তাই বারবার ব্যবহারে ধীর।- namespace কেন? — বিভিন্ন library বা অংশের একই নামের জিনিসকে আলাদা রাখতে; standard library থাকে
std-এ। main-এreturn 0;না লিখলে কী হয়? — শুধুmain-এর ক্ষেত্রে compiler ধরে নেয় 0 ফেরত; অন্যintফাংশনে এটি ভুল (undefined behavior).cout << a << bকীভাবে কাজ করে? — প্রতিটি<<একটি overloaded ফাংশন, যা stream-টিই ফেরত দেয়; তাই বাঁ থেকে ডানে চেইন হয়।
৭ · প্রথম দিনের ভুল — g++-এর মেসেজ পড়তে শিখুন
প্রথম সপ্তাহে প্রায় সবাই একই কয়েকটি ভুল করেন। ভালো খবর: আধুনিক g++ অনেক সময় সমাধানও বলে দেয় (did you mean …?)। মেসেজের শুরুর অংশ hello.cpp:3:5: মানে ফাইল hello.cpp, লাইন 3, কলাম 5. আর মনে রাখুন — ভুল প্রায়ই দেখানো লাইনের ঠিক আগের লাইনে থাকে।
| ভুল | g++ যা বলে | সমাধান |
|---|---|---|
; বাদ পড়েছে | error: expected ';' before 'return' | আগের লাইনের শেষে ; দিন |
std:: ছাড়া cout | error: 'cout' was not declared in this scope; did you mean 'std::cout'? | std::cout লিখুন |
#include <iostream> ভুলে গেছেন | error: 'cout' is not a member of 'std' (সাথে note: this is probably fixable by adding '#include <iostream>') | শুরুতে #include যোগ করুন |
<<-এর বদলে >> | error: no match for 'operator>>' (operand types are 'std::ostream' … and 'const char [4]') | cout-এর সাথে <<, cin-এর সাথে >> |
" বন্ধ করা হয়নি | error: missing terminating " character | লেখার শেষে কোট দিন |
Main (বড় হাতের M) | undefined reference to `main' (linker থেকে) | ছোট হাতের main |
| WhatsApp/Word থেকে বাঁকা কোট (“ ”) | error: extended character “ is not valid in an identifier (পুরোনো g++-এ stray '\342' in program) | কোট মুছে কিবোর্ড থেকে " টাইপ করুন |
>>-এর error-টি ভয়ংকর লম্বা হয় — কয়েক ডজন লাইন “candidate” দেখায়। ঘাবড়াবেন না; শুধু প্রথম error: লাইনটি পড়ুন। সেখানে স্পষ্ট লেখা: std::ostream (অর্থাৎ cout)-এর সাথে >> মেলে না। বাঁকা কোটের ব্যাপারটা হলো, এগুলো ASCII অক্ষর নয়, UTF-8-এ ৩ byte-এর একটি অক্ষর; compiler একে লেখার শুরু হিসেবে চেনে না, ফলে “Hi”-কে কোনো অজানা নাম ভাবে। C কোর্সের পর্ব ০৪-এ এর byte-স্তরের ব্যাখ্যা আছে।
এবার একটি বাস্তব দৃশ্য — একটি প্রোগ্রামে তিনটি ভুল একসাথে। দেখুন compiler সব ভুল একবারে দেখায় না; একটি ঠিক করলে পরেরটি সামনে আসে:
#include <iostream>
int Main() {
cout << "Hello" << '\n'
return 0;
}
hello.cpp:3:5: error: 'cout' was not declared in this scope;
did you mean 'std::cout'?
#include <iostream>
int Main() {
std::cout << "Hello" << '\n'_
return 0;
}
hello.cpp:3:33: error: expected ';' before 'return'
#include <iostream> int Main() { std::cout << "Hello" << '\n'; return 0; } /usr/bin/ld: ... in function `_start': undefined reference to `main' collect2: error: ld returned 1 exit status
#include <iostream>
int main() {
std::cout << "Hello" << '\n';
return 0;
}
$ g++ -Wall -Wextra hello.cpp -o hello
$ ./hello
Hello
$ echo $?
0
- প্রথম error. কোডে আসলে তিনটি ভুল, কিন্তু g++ দেখাল একটি:
coutচেনে না। সাথে পরামর্শ —std::cout? লক্ষ্য করুন, বাদ পড়া;-এর কথা বলেনি; প্রথম ভুলে বিভ্রান্ত হয়ে compiler সেই লাইনের বাকিটা ঠিকমতো বিচারই করতে পারেনি। নিয়ম: সবসময় ওপরের প্রথম error আগে ঠিক করুন, তারপর আবার compile. - দ্বিতীয় error.
std::যোগ করতেই নতুন মেসেজ:expected ';' before 'return'. Compilerreturnশব্দে পৌঁছে বুঝল আগের statement শেষ হয়নি — তাই লাইন নম্বর দেখায় ঠিক আগের লাইনের শেষ। লাল দাগের জায়গায়;বসান। - Compile পার, কিন্তু link-এ আটকাল। এবার মেসেজ এসেছে
ldথেকে — অর্থাৎ পর্ব ০৩-এর linker. Compiler-এর কাছেMainএকটি বৈধ ফাংশন, কোনো আপত্তি নেই। কিন্তু startup code (_start) খোঁজে ঠিকmain, পেল না। Case-sensitivity-র ফল! - শেষ সংশোধন।
Main→main. তিনটি ভুল, তিনটি আলাদা ধরন: নাম না চেনা (compiler), ব্যাকরণ (compiler), প্রবেশপথ না পাওয়া (linker). মেসেজের উৎস দেখে ধরন চেনা — এটাই পর্ব ০৩ আর এই পর্বের মিলনবিন্দু। - চলল, exit code 0. কোনো error নেই,
-Wall -Wextraদিয়েও একটি warning নেই। শিক্ষা: error-এর লম্বা তালিকা দেখে ভয় পাবেন না; প্রায়ই একটি মূল ভুল থেকে বাকিগুলো জন্মায়। প্রথমটি ঠিক করুন, আবার চালান।
কোড শেয়ার করার সময় সাধারণ টেক্সট হিসেবে পাঠান — GitHub Gist, Pastebin, অথবা WhatsApp-এ তিনটি backtick (```) দিয়ে ঘিরে। তাহলে কোট বাঁকা হয় না। আর VS Code-এর মতো editor অ-ASCII অক্ষরকে আলাদা রঙে বা বাক্সে দেখায়, খেয়াল রাখলেই ধরা পড়ে।
৮ · AI-এর যুগে — AI-এর লেখা “Hello World” যাচাই
AI-কে “একটা C++ প্রোগ্রাম লিখে দাও” বললে প্রায়ই প্রথম দুই লাইন হয় এমন:
#include <bits/stdc++.h>
using namespace std;
AI এগুলো শিখেছে লাখো কনটেস্ট সমাধান থেকে। bits/stdc++.h একটি header, যা একবারে প্রায় সব standard header এনে দেয় — কনটেস্টে সময় বাঁচে। কিন্তু এটি standard C++-এর অংশ নয়; এটি GCC-র library (libstdc++)-এর ভেতরের একটি সুবিধা। Microsoft-এর Visual C++-এ এটি নেই, আর Mac-এর ডিফল্ট Clang (যা libc++ ব্যবহার করে) সাধারণত এটি খুঁজে পায় না। তার ওপর সবকিছু একসাথে আনায় compile-এর সময়ও বাড়ে।
যেখানে চলে
Codeforces, AtCoder, ICPC-র মতো কনটেস্টে, যেখানে বিচারক GCC ব্যবহার করে, কোড একবার চলবে, আর কেউ রক্ষণাবেক্ষণ করবে না। পর্ব ৫০-এ কনটেস্টের কৌশল আলাদা করে দেখবেন।
কনটেস্ট, দ্রুত পরীক্ষাযেখানে চলে না
অফিসের প্রজেক্ট, ওপেন সোর্স, header ফাইল, ইন্টারভিউয়ের লিখিত কোড — যেখানে কোড অন্য compiler-এ চলবে, অন্য মানুষ পড়বে, বছরের পর বছর টিকে থাকবে।
প্রজেক্ট, লাইব্রেরি, দলের কোডAI আর পুরোনো নোটের সাধারণ অভ্যাস
| যা দেখবেন | সমস্যা | যা লিখবেন |
|---|---|---|
#include <bits/stdc++.h> | অ-standard, শুধু GCC-তে | যা লাগে তার header: <iostream>, <string>… |
লুপের ভেতরে std::endl | প্রতিবার flush, ধীর | '\n' |
#include <iostream.h>, void main() | Standard-এর আগের যুগের কোড, আধুনিক compiler-এ error | <iostream>, int main() |
system("pause"), getch() | শুধু Windows-এ চলে | বাদ দিন; IDE বা terminal থেকে চালান |
header-এ using namespace std; | সব include-কারী ফাইলে নামের সংঘাত ছড়ায় | header-এ সবসময় std:: |
AI-কে আগে থেকেই নিয়ম বলে দিন। তাহলে কোড শুরু থেকেই পেশাদার মানের হয়, আর প্রতিটি লাইনের ব্যাখ্যাও পান:
AI-এর লেখা প্রথম প্রোগ্রাম যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে কোড-লেখক থেকে সিস্টেম-চিন্তক বানাবে।
প্র ০১C-তে তো printf ছিলই — C++ কেন << বানাল? আর এত বছর পর C++20/23 আবার {} placeholder-এর দিকে ফিরল কেন?
printf-এর দুটি মৌলিক দুর্বলতা ছিল, যা C++-এর নকশাকারদের চোখে বড় হয়ে ধরা দেয়।
- টাইপ-নিরাপত্তা নেই:
printf("%d", 3.5)লিখলে C compiler নিয়মমতো বাধা দিতে পারে না — format string শুধু একটি লেখা, আর আর্গুমেন্টের টাইপ মিলছে কি না তা চালানোর সময়ও কেউ দেখে না। ফল আবর্জনা মান, এমনকি ক্র্যাশ। আধুনিক compiler warning দেয় ঠিকই, কিন্তু সেটা ভাষার নিয়ম নয়, বাড়তি সুবিধা। আরও খারাপ, ব্যবহারকারীর লেখা সরাসরি format string হিসেবে দিলে (printf(user_input)) “format string attack” নামের নিরাপত্তা-ত্রুটি তৈরি হয়। - বাড়ানো যায় না: নিজের বানানো টাইপ, ধরুন
Date, ছাপাতেprintf-কে শেখানোর উপায় নেই —%Dateবলে কিছু হয় না।
<< দুটিই মেটায়: compiler প্রতিটি মানের টাইপ দেখে ঠিক ফাংশনটি বেছে নেয়, আর যে কেউ নিজের টাইপের জন্য নতুন << লিখতে পারে। ১৯৮০-এর দশকে Stroustrup-এর প্রথম stream library-কে পরে Jerry Schwarz নতুন করে নকশা করেন — সেটিই আজকের iostream-এর পূর্বসূরি।
কিন্তু কয়েক দশকের ব্যবহারে iostream-এর দাম চোখে পড়ে। বাক্য টুকরো হয়ে যায়, তাই অনুবাদ কঠিন — বাংলায় শব্দের ক্রম ইংরেজির মতো নয়, অথচ <<-এর চেইনে ক্রম কোডেই বাঁধা। std::hex-এর মতো format-বদল stream-এ “আটকে থাকে”, পরের সব লাইনে প্রভাব ফেলে — লুকানো বাগের উৎস। আর গতিও প্রায়ই printf-এর চেয়ে কম।
সমাধান এল ভাষার বাইরে থেকে। Victor Zverovich-এর ওপেন সোর্স library {fmt} দেখাল, placeholder রেখেও টাইপ-নিরাপদ হওয়া যায় — format string compile-এর সময়েই যাচাই হয়। এর ভিত্তিতে C++20-এ এল std::format, C++23-এ std::print. অর্থাৎ ফেরা হয়েছে printf-এর চেহারায়, কিন্তু <<-এর নিরাপত্তা রেখে।
মূল উপলব্ধি: ভাষার নকশা একবারে নিখুঁত হয় না। একটি সমস্যা (টাইপ-নিরাপত্তা) মেটাতে গিয়ে আরেকটি দাম (পাঠযোগ্যতা) দিতে হয়েছিল; প্রযুক্তি এগোলে দুটোই পাওয়ার পথ বেরোয়। ভালো ইঞ্জিনিয়ার জানেন কোন যুগের কোন সমাধান কোন দাম দিয়ে কেনা।
প্র ০২দশ লাখ লাইন ছাপানোর লুপে std::endl দিলে প্রোগ্রাম এত ধীর হয় কেন? Buffer আসলে কী বাঁচায়?
স্ক্রিনে বা ফাইলে লেখা আপনার প্রোগ্রাম নিজে করতে পারে না — এটি অপারেটিং সিস্টেমের কাজ। প্রতিবার লেখা পাঠাতে প্রোগ্রামকে OS-কে ডাকতে হয়; একে বলে system call (Linux-এ write). প্রতিটি system call-এ CPU সাধারণ প্রোগ্রামের অবস্থা থেকে OS-এর বিশেষ অবস্থায় যায়, কাজ করে, আবার ফেরে। একটি ফাংশন ডাকার তুলনায় এটি অনেক গুণ বেশি সময় নেয়।
Buffer এই খরচ ভাগ করে নেয়। Stream লেখাগুলো মেমরিতে জমায়, আর কয়েক হাজার byte জমলে একটিমাত্র system call-এ পাঠায়। দশ লাখ লাইন হয়তো কয়েকশো system call-এই চলে যায়। কিন্তু প্রতিটি লাইনের পর std::endl দিলে buffer প্রতিবার খালি করতে হয় — দশ লাখ লাইন মানে দশ লাখ system call. আউটপুট যদি ফাইলে বা অন্য প্রোগ্রামে যায় (যেমন কনটেস্টের judge-এ), পার্থক্য আরও স্পষ্ট হয়। কনটেস্টে “Time Limit Exceeded” পাওয়ার একটি পরিচিত কারণ এটাই।
কনটেস্ট প্রোগ্রামাররা আরও দুটি লাইন লেখেন: std::ios::sync_with_stdio(false); আর std::cin.tie(nullptr);. প্রথমটি C-র printf/scanf-এর সাথে iostream-এর সমন্বয় বন্ধ করে, যাতে iostream নিজের buffer পুরোপুরি ব্যবহার করতে পারে; দ্বিতীয়টি প্রতিটি cin-এর আগে cout flush করা বন্ধ করে। এর দাম আছে — এরপর printf আর cout মেশালে আউটপুটের ক্রম এলোমেলো হতে পারে, আর interactive প্রোগ্রামে প্রশ্নটা ইনপুট চাওয়ার আগে দেখা নাও যেতে পারে। পর্ব ৫০-এ এ নিয়ে বিস্তারিত।
তাহলে flush কি খারাপ? না — কখন লাগে বুঝতে হবে। প্রোগ্রাম ক্র্যাশ করলে buffer-এ আটকে থাকা লেখা হারিয়ে যায়। তাই error লগ তাৎক্ষণিক যাওয়া দরকার — এজন্যই std::cerr-এর buffer নেই।
মূল উপলব্ধি: “জমিয়ে একসাথে পাঠানো” (batching) কম্পিউটিংয়ের সবচেয়ে কার্যকর কৌশলগুলোর একটি — ডিস্ক, নেটওয়ার্ক, ডেটাবেস সবখানে। তার উল্টো পিঠে থাকে দেরি আর হারানোর ঝুঁকি। গতি বনাম তাৎক্ষণিকতা — এই trade-off চিনলে অনেক পারফরম্যান্স রহস্য খুলে যায়।
প্র ০৩main-এর ফেরত দেওয়া ছোট্ট সংখ্যাটি অপারেটিং সিস্টেম, script আর CI-এর কাছে কী অর্থ বহন করে?
Unix-এর শুরু থেকেই একটি দর্শন ছিল: ছোট ছোট প্রোগ্রাম, প্রত্যেকে একটি কাজ ভালোভাবে করে, আর এগুলো জোড়া দিয়ে বড় কাজ হয়। জোড়া দিতে হলে প্রতিটি প্রোগ্রামকে জানাতে হয় তার কাজ সফল হলো কি না। স্ক্রিনের লেখা মানুষের জন্য; কিন্তু অন্য প্রোগ্রামের জন্য দরকার একটি সহজ, যন্ত্রে-পড়ার-মতো সংকেত — সেটিই exit code.
- Shell:
g++ main.cpp -o main && ./main— compile ব্যর্থ হলে (exit code অশূন্য) পুরোনোmainভুল করে চলবে না।||দিয়ে উল্টোটাও করা যায়: ব্যর্থ হলে বিকল্প কাজ। - Build system: Make বা CMake (পর্ব ৪৭) কোনো ধাপ অশূন্য ফেরত দিলেই থেমে যায়, যাতে ভাঙা জিনিসের ওপর আরও কিছু না গড়ে।
- CI: GitHub Actions-এর মতো সিস্টেম প্রতিটি কমান্ডের exit code দেখে। টেস্ট প্রোগ্রাম 1 ফেরত দিলে pull request-এ লাল ক্রস — কোড merge হবে না। পুরো আধুনিক সফটওয়্যার কারখানা এই একটি সংখ্যার ওপর দাঁড়িয়ে।
- Container ও সার্ভার: Docker বা Kubernetes দেখে কোনো সার্ভিস কোন exit code দিয়ে থামল, আর সেই অনুযায়ী আবার চালু করার সিদ্ধান্ত নেয়।
কিছু প্রোগ্রাম অশূন্য সংখ্যাগুলোকেও অর্থ দেয়। যেমন খোঁজার টুল grep: মিল পেলে 0, না পেলে 1, আর কোনো error হলে 2. তাই script বুঝতে পারে “পাওয়া যায়নি” আর “খুঁজতেই পারিনি” আলাদা কথা। Linux-এ সংখ্যাটির শুধু নিচের ৮ bit পৌঁছায় (0–255), তাই বড় সংখ্যা ফেরত দেওয়া বিপজ্জনক: return 256; shell-এ 0 হয়ে “সফল” দেখায়।
এজন্যই AI-এর লেখা কোডে error হলে শুধু মেসেজ ছাপিয়ে return 0; করা একটি সূক্ষ্ম কিন্তু গুরুতর বাগ — মানুষ বুঝবে ব্যর্থ, কিন্তু script আর CI ভাববে সব ঠিক।
মূল উপলব্ধি: আপনার প্রোগ্রাম একা চলে না; সে একটি বড় ব্যবস্থার অংশ। মানুষের জন্য লেখা আর যন্ত্রের জন্য সংকেত — দুটোই সৎ হতে হবে। ব্যর্থ হলে অশূন্য ফেরত দেওয়া একটি ছোট শিষ্টাচার, যার ওপর পুরো automation নির্ভর করে।
প্র ০৪প্রথম দিকের C++-এ namespace ছিল না। পরে standard বানানোর সময় এটি কেন যোগ করতে হলো, আর পুরোনো <iostream.h>-এর সাথে এর সম্পর্ক কী?
১৯৮০-এর দশকের C++ (তখন Stroustrup-এর cfront compiler দিয়ে চলত) ছিল C-র মতোই: সব নাম এক বিশাল সাধারণ জায়গায়। ছোট প্রোগ্রামে সমস্যা নেই। কিন্তু C++ যখন বড় কোম্পানিতে ছড়াল, একটি প্রোগ্রামে কয়েকটি কোম্পানির library একসাথে লাগল — একটির String, আরেকটির String, তৃতীয়টির List. দুটি library একসাথে include করলেই compile বন্ধ।
তখনকার ঠেকনা ছিল উপসর্গ: প্রতিটি নামের আগে library-র চিহ্ন। C জগতে আজও এটি দেখবেন — PNG library-র ফাংশন png_ দিয়ে শুরু, OpenGL-এর gl দিয়ে; আর Qt-এর ক্লাস Q দিয়ে (QString). কাজ চলে, কিন্তু নাম লম্বা হয়, আর দুটি library একই উপসর্গ বেছে নিলে আবার সংঘাত।
১৯৯০-এর দশকের শুরুতে ISO/ANSI কমিটি যখন C++-কে আনুষ্ঠানিক standard বানাচ্ছিল, তারা বুঝল standard library নিজেই বড় হতে চলেছে — string, container, algorithm. এগুলো সাধারণ জায়গায় রাখলে ব্যবহারকারীর কোডের সাথে সংঘাত অনিবার্য। তাই ভাষায় যোগ হলো namespace, আর ১৯৯৮ সালের প্রথম ISO standard-এ (C++98) পুরো standard library রাখা হলো std-এর ভেতরে। সাথে header-এর নামও বদলাল: <iostream.h> (namespace-হীন পুরোনো সংস্করণ) থেকে <iostream>.
বাংলাদেশের অনেক কলেজ ও বিশ্ববিদ্যালয়ে বহু বছর Turbo C++ চলেছে, যা standard-এর আগের যুগের compiler — সেখানে <iostream.h> লিখতে হতো, std:: লাগত না। পুরোনো নোট আর গাইড বইয়ে আজও সেই কোড ঘোরে, আর আধুনিক g++-এ iostream.h: No such file or directory দেখায়। এখন আপনি জানেন কেন।
আর using namespace std;-এর জনপ্রিয়তা? সেটি ছিল রূপান্তরের সেতু — পুরোনো কোডকে কম পরিশ্রমে নতুন standard-এ চালানোর উপায়। সেতু পার হয়ে গেলে তার ওপর বাড়ি বানানো উচিত নয়।
মূল উপলব্ধি: ভাষার অনেক নিয়ম আসে “বড় হওয়ার ব্যথা” থেকে। একজনের কোডে যা অপ্রয়োজনীয় মনে হয়, হাজার মানুষের কোড একসাথে মেলাতে গেলে তা-ই অপরিহার্য। namespace হলো দলগতভাবে সফটওয়্যার বানানোর জন্য ভাষার জবাব।
প্র ০৫একই “Hello” ছাপানো C++ প্রোগ্রামের ফাইল প্রায়ই C প্রোগ্রামের চেয়ে বড় হয়, আর চালু হতেও সামান্য বেশি সময় নেয়। কেন?
C++-এর একটি বিখ্যাত নীতি আছে — zero-overhead principle: যা ব্যবহার করেন না, তার দাম দিতে হবে না। কিন্তু iostream এই নীতির সবচেয়ে আলোচিত ব্যতিক্রমগুলোর একটি।
- Static initialization:
std::coutএকটি সত্যিকারের object, যাmainশুরুর আগেই তৈরি ও প্রস্তুত থাকতে হয়। iostream-এর ব্যবস্থায় তাই প্রোগ্রাম চালুর মুহূর্তে কিছু কাজ হয় —cout,cin,cerr,clogআর তাদের wide-character সংস্করণ বানানো, buffer সাজানো।printf-এর এমন কিছু লাগে না। - Locale ও বহুমুখিতা: একটি stream সংখ্যা ছাপানোর সময় locale (দেশভেদে দশমিক চিহ্ন, হাজারের বিভাজক) মানতে পারে। আপনি ব্যবহার না করলেও এই যন্ত্রপাতির বড় অংশ প্রোগ্রামের সাথে যুক্ত হয়।
- Linking-এর ধরন: Linux-এ C++ library (libstdc++) সাধারণত dynamic ভাবে জোড়া হয়, তাই ফাইল ছোটই থাকে। কিন্তু Windows-এ MinGW দিয়ে
-staticকরলে সব যন্ত্রপাতি ফাইলের ভেতরে ঢুকে যায় — একটি “Hello” কয়েক MB পর্যন্ত হতে পারে। static বনাম dynamic linking-এর trade-off (C কোর্সের টুলচেইন পর্বে বিস্তারিত) এখানে চোখে দেখা যায়।
এটা কি বড় সমস্যা? ডেস্কটপ বা সার্ভারে সাধারণত না — কয়েক MB বা কয়েক microsecond কারও চোখে পড়ে না। কিন্তু embedded সিস্টেমে, যেখানে পুরো মেমরি কয়েকশো KB, এটি গুরুতর। এজন্য অনেক embedded C++ প্রজেক্ট iostream ব্যবহারই করে না, আর library বানানেওয়ালারাও এই খরচ কমাতে কাজ করে চলেছেন — নতুন কিছু GCC version-এ এই প্রস্তুতির কাজ আপনার প্রতিটি ফাইল থেকে সরিয়ে library-র ভেতরে নেওয়া হয়েছে।
নিজে মাপতে চাইলে দুটি প্রোগ্রাম বানিয়ে (একটি printf, একটি std::cout) -O2 দিয়ে compile করুন, তারপর ফাইলের আকার তুলনা করুন — একবার সাধারণভাবে, একবার -static দিয়ে। অনুমান নয়, মাপুন — পর্ব ৪৯-এর মূল কথাও এটাই।
মূল উপলব্ধি: প্রতিটি সুবিধা — টাইপ-নিরাপত্তা, বাড়ানোর ক্ষমতা, locale — কোথাও না কোথাও দাম নেয়। পেশাদার প্রশ্ন হলো “এই প্রজেক্টে এই দাম গ্রহণযোগ্য কি?” মোবাইল অ্যাপ আর মাইক্রোকন্ট্রোলারের উত্তর আলাদা।
অনুশীলন
বেশিরভাগই ভাবা আর হাতে-কলমে দেখার কাজ — শুধু শেষটিতে নিজে কোড লিখবেন।
-
আউটপুট অনুমান করুন: চালানোর আগে খাতায় লিখুন, তারপর মিলিয়ে দেখুন —
std::cout << 1 << 2 << '\n' << 5 + 3 << "\n";প্রথম লাইনে
12(মাঝে কোনো ফাঁকা নেই — stream নিজে থেকে space বসায় না!), দ্বিতীয় লাইনে8. চেইন বাঁ থেকে ডানে চলে;5 + 3-এর+অপারেটর<<-এর চেয়ে শক্তিশালী, তাই যোগ আগে হয়ে 8 ছাপা হয়।'\n'আর"\n"দুটোই একই কাজ করেছে। শিক্ষা: সংখ্যার মাঝে ফাঁকা চাইলে নিজেই' 'দিতে হবে। -
Exit code নিয়ে পরীক্ষা: নিজের কম্পিউটারে
int main() { return 7; }compile করে চালান, তারপরecho $?(PowerShell-এecho $LASTEXITCODE) দেখুন। এরপর 7-এর বদলে 256 দিন। Linux-এ কী দেখলেন, কেন?প্রথমবার দেখবেন
7. দ্বিতীয়বার Linux বা Mac-এ দেখবেন0, কারণ shell শুধু নিচের ৮ bit পায় — 256 = 1 0000 0000 (বাইনারি), নিচের ৮ bit সব শূন্য। অর্থাৎ ব্যর্থতা জানাতে চেয়ে আপনি ভুল করে “সফল” জানালেন! Windows-এ exit code ৩২ bit-এর, তাই সেখানে 256-ই দেখবেন — এক প্ল্যাটফর্মের ধারণা অন্যটিতে খাটে না। নিরাপদ নিয়ম: 0 সফল, 1 (বাEXIT_FAILURE) ব্যর্থ। -
Error গোয়েন্দা: নিচের তিনটি মেসেজ দেখে বলুন ভুলটা কী, আর কোনটা compiler-এর, কোনটা linker-এর — (ক)
error: 'string' was not declared in this scope; did you mean 'std::string'?(খ)undefined reference to `main'(গ)error: no match for 'operator<<' (operand types are 'std::istream' …)(ক) Compiler —
std::ছাড়াstringলেখা হয়েছে (বা<string>include করা হয়নি — তখন মেসেজ হতোis not a member of 'std').(খ) Linker —
mainনেই; সম্ভবতMainবাmianলেখা হয়েছে, অথবা ফাইলটিতেmain-ই নেই।(গ) Compiler —
std::istreamমানেcin. কেউstd::cin << xলিখেছে;cin-এর সাথে>>লাগে। মনে রাখার কৌশল: তীর দেখায় ডেটা কোন দিকে যাচ্ছে। -
নিজের namespace (কোড লিখুন):
metroনামে একটি namespace বানান, যার ভেতরেticket()ফাংশন ছাপাবেUttara to Motijheel. আরেকটি namespacebus-এ একই নামেরticket()ছাপাবেGabtoli to Sadarghat.mainথেকে দুটোই ডাকুন, আর শেষ লাইনটিstd::printlnদিয়ে ছাপান।#include <iostream> #include <print> namespace metro { void ticket() { std::cout << "Uttara to Motijheel\n"; } } namespace bus { void ticket() { std::cout << "Gabtoli to Sadarghat\n"; } } int main() { metro::ticket(); bus::ticket(); std::println("{} tickets printed", 2); }যাচাই করুন:
using namespace metro;আরusing namespace bus;দুটো যোগ করে শুধুticket();লিখলে কী হয়?ambiguouserror — ঠিক অংশ ৫-এর মতো। আরmain-এreturnনা থাকলেও সমস্যা নেই।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি C++ প্রোগ্রামের যাত্রা সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- ✍️
hello.cppফাইলে কোড লেখা - 📦 Preprocessor
<iostream>-এর ঘোষণা এনে বসায় - 📐 Compiler ব্যাকরণ যাচাই করে machine code বানায়
- 🧵 Linker library জুড়ে
mainখুঁজে প্রোগ্রাম বানায় - 🖥️ OS প্রোগ্রাম চালু করে
mainডাকে,std::coutলেখা ছাপে - 🔚
main0 ফেরত দেয়, shell exit code পায়
std::cout << "A" << 1 << 2 << '\n'; চালালে স্ক্রিনে কী আসবে?
- A 1 2
- A12
- A3
- A12\n
std::endl আর '\n'-এর মূল পার্থক্য কী?
- '\n' শুধু Linux-এ কাজ করে
- std::endl দুটি নতুন লাইন দেয়
- std::endl নতুন লাইনের সাথে buffer flush-ও করে
- '\n' প্রতিবার flush করে, তাই ধীর
C++-এ int main()-এর শেষে return statement না লিখলে কী হয়?
- main যেন return 0; করেছে — এমন ধরা হয়
- Compile error হয়
- যেকোনো আবর্জনা মান ফেরত যায়
- প্রোগ্রাম ক্র্যাশ করে
Header ফাইলে using namespace std; লেখা কেন খারাপ অভ্যাস?
- প্রোগ্রাম চালানোর সময় ধীর হয়ে যায়
- Header-এ এটি লিখলে compile error হয়
- std-এর ফাংশনগুলো আর ব্যবহার করা যায় না
- যে ফাইলই header-টি include করে, তাতে std-এর সব নাম ঢুকে নামের সংঘাত ঘটাতে পারে
#include <bits/stdc++.h> সম্পর্কে কোন কথাটি সঠিক?
- এটি C++17 থেকে standard-এর অংশ
- এটি GCC-নির্দিষ্ট; সব compiler-এ পাওয়া যায় না
- এটি compile দ্রুত করে, কারণ ছোট ফাইল
- এটি থাকলে std:: লেখার দরকার হয় না
std::string name; std::cin >> name; — ব্যবহারকারী লিখলেন Rafi Ahmed তারপর Enter. name-এ কী থাকবে?
- Rafi Ahmed
- Ahmed
- Rafi
- কিছুই না, error হয়
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
#include <iostream>যন্ত্র আনে,int main()শুরুর দরজা, প্রতিটি statement শেষ হয়;দিয়ে, আর C++ বড়-ছোট হাতের অক্ষর আলাদা ধরে।std::coutএকটি stream; প্রতিটি<<একই stream ফেরত দেয়, তাই বাঁ থেকে ডানে চেইন. নতুন লাইনে'\n';std::endlশুধু flush দরকার হলে। error-এর জন্যstd::cerr.- namespace হলো পদবি:
std::দিয়ে সংঘাত এড়ানো।using namespace std;কনটেস্টে চলে, header ও বড় প্রজেক্টে নয়; মাঝামাঝি পথusing std::cout;. - C++23 থেকে
std::println("{}", x)— placeholder দিয়ে পাঠযোগ্য, টাইপ-নিরাপদ আউটপুট। main-এর ফেরত মান হলো exit code: 0 সফল, অশূন্য ব্যর্থ — shell, build system আর CI এর ওপর সিদ্ধান্ত নেয়। Error এলে প্রথমটি আগে ঠিক করুন।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৫ · টাইপ, auto আর const — ডেটার বাক্সপরবর্তী পর্বভ্যারিয়েবল, টাইপ আর
auto— ডেটা কীভাবে মেমরিতে থাকে। - C++ প্রোগ্রামিং · কোর্স হোম৫৫টি পর্বপুরো কোর্সের রোডম্যাপ — কোন পর্ব কখন।
- পর্ব ০৩ · টুলচেইন — g++, compile আর linkআগের পর্বerror কোন ধাপের — compiler না linker — আবার ঝালিয়ে নিন।
- C প্রোগ্রামিং · পর্ব ০৪ — প্রথম প্রোগ্রামপাশের ট্র্যাক
printf, format specifier আর smart quote-এর byte-স্তরের রহস্য।