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

লুপ (Loops)

আধুনিক সুবিধাগুলোর সাথে পুরোনো ক্লাসিকগুলোর মিল — এখানকার রেঞ্জ-বেসড (range-based) ফর লুপটিই (for) হলো এর মূল আকর্ষণ

লুপ ফ্যামিলি বা লুপ পরিবার (The Loop Family)

যেকোনো প্রোগ্রামিংয়ের ক্ষেত্রেই লুপগুলোকে (Loops) মূলত এর ওয়ার্কহর্স বা অশ্বশক্তি (workhorses) বলা হয় — এরা মূলত কোনো একটি ব্লক বা কোডকে (block of code) ততক্ষণ পর্যন্ত রিপিট (repeat) করে বা পুনরাবৃত্তি করে, যতক্ষণ না পর্যন্ত এর ভেতরের কোনো একটি শর্ত পূরণ (condition is met) হচ্ছে। সি++ (C++) মূলত সি (C) থেকে উত্তরাধিকারসূত্রে পাওয়া এর তিনটি ক্লাসিক লুপ (classic loop) ফর্মকেই (for, while, do-while) গ্রহণ করেছে এবং এর সাথে আধুনিক যুগের এক সুপারস্টার বা নতুন বৈশিষ্ট্যকেও (modern superstar) যুক্ত করেছে: আর তা হলো এখানকার রেঞ্জ-বেসড ফর লুপ (range-based for loop)

যদি এই ক্লাসিক ফর লুপটিকে (classic for loop) একটি ম্যানুয়াল ট্রান্সমিশনের (manual transmission) গাড়ির সাথে তুলনা করা হয় — যা অত্যন্ত শক্তিশালী (powerful) হলেও এর প্রতিটি গিয়ার আপনাকেই ঠিকমতো বদলাতে (gear shift) হয় — তবে এই রেঞ্জ-বেসড ফর লুপটি (range-based for) হলো অনেকটা একটি অটোমেটিক ট্রান্সমিশনের (automatic transmission) মতো। গন্তব্য একই (Same destination), তবে এতে প্যারা অনেক কম (less fiddling)।

ক্লাসিক ফর লুপ (The Classic for Loop)

#include <iostream>
using namespace std;
int main() {
// ক্লাসিক ফর লুপ (Classic for) — এক্ষেত্রে এর init, condition, এবং increment সবকিছুই আপনার এর নিয়ন্ত্রণে বা control থাকে
cout << "Counting up: ";
for (int i = 1; i <= 5; i++) {
cout << i << " ";
}
cout << endl;
// নিচের দিকে কাউন্টিং (Counting down)
cout << "Countdown: ";
for (int i = 5; i > 0; i--) {
cout << i << " ";
}
cout << "Liftoff!" << endl;
// ২ করে লাফানো বা Stepping by 2
cout << "Evens: ";
for (int i = 0; i <= 10; i += 2) {
cout << i << " ";
}
cout << endl;
return 0;
}
Output
Counting up: 1 2 3 4 5
Countdown: 5 4 3 2 1 Liftoff!
Evens: 0 2 4 6 8 10

while এবং do-while

এই while মূলত এর প্রতিটি ইটারেশন বা চক্রের আগেই (before) এর শর্তটি (condition) চেক (checks) করে — যদি শর্তটি একেবারে শুরুতেই ফলস (false) বা মিথ্যা হয়ে যায়, তবে এর ভেতরের বডিটি (body) আর কখনোই রান (runs) করে না। কিন্তু do-while মূলত এটি পরে (after) চেক করে — আর এই কারণে এর বডিটি (body) সব সময়ই অন্ততপক্ষে একবারের (at least once) জন্য হলেও রান করে।

এই do-while মূলত বিভিন্ন মেনু (menus) তৈরির জন্য একেবারে পারফেক্ট (perfect): কারণ ব্যবহারকারীকে বা user-কে সে আরও এগিয়ে (continue) যেতে চায় কি না তা জিজ্ঞেস করার আগে, আপনি সব সময়ই তাকে একবারের জন্য হলেও এর মেনুটি (menu) দেখাতে চাইবেন।

while এবং do-while

#include <iostream>
using namespace std;
int main() {
// while — এটি হয়তো একবারও এক্সিকিউট (execute) নাও করতে পারে
int fuel = 3;
cout << "Driving..." << endl;
while (fuel > 0) {
cout << " Fuel left: " << fuel << endl;
fuel--;
}
cout << "Out of gas!" << endl;
cout << endl;
// do-while — এটি সব সময়ই অন্তত একবার রান করে (always executes at least once) (মেনুগুলোর জন্য এটি গ্রেট বা দারুণ)
int choice;
do {
cout << "--- Menu ---" << endl;
cout << "1. Play" << endl;
cout << "2. Settings" << endl;
cout << "3. Quit" << endl;
choice = 3; // ব্যবহারকারী Quit নির্বাচন করছে এমনটা দেখানো বা simulate করা
cout << "You chose: " << choice << endl;
} while (choice != 3);
cout << "Goodbye!" << endl;
return 0;
}
Output
Driving...
  Fuel left: 3
  Fuel left: 2
  Fuel left: 1
Out of gas!

--- Menu ---
1. Play
2. Settings
3. Quit
You chose: 3
Goodbye!

রেঞ্জ বেসড ফর লুপ (Range-Based for) — এখানকার মূল আকর্ষণ (The Star of the Show)

সি++১১ (C++11)-এ যুক্ত হওয়া এই রেঞ্জ-বেসড ফর লুপটি (range-based for loop) হলো যেকোনো কালেকশনের (collections) ওপর ইটারেট (iterate) করার জন্য সবচেয়ে আধুনিক (modern) একটি উপায়। এতে কোনো ধরনের ইনডেক্স ম্যানেজমেন্ট (index management), বিভিন্ন অফ-বাই-ওয়ান এরর (off-by-one errors) বা কোনো ইটারেটর বয়লারপ্লেটেরও (iterator boilerplate) প্রয়োজন পড়ে না। শুধু সি++ (C++)-কে বলে দিলেই হয় যে এটি ঠিক কোন জিনিসের ওপর লুপ (loop) তৈরি করবে, এরপর বাকি সবকিছুই এটি নিজেই সামলে (handles the rest) নেয়।

এর সাধারণ নিয়ম বা সিনট্যাক্সটি (syntax) হলো: for (auto& element : collection)

এটিকে আপনি অনেকটা এমনভাবে চিন্তা করতে পারেন যেন আপনি বলছেন: "এই কালেকশনের ভেতরের প্রতিটি এলিমেন্টের জন্য (for each element in this collection), এই কাজগুলো করো (do something)।"

ভেক্টরগুলোর সাথে রেঞ্জ-বেসড ফর লুপ (Range-Based for)

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<int> scores = {95, 87, 92, 78, 100};
// রেঞ্জ-বেসড ফর লুপ বা Range-based for — পরিষ্কার (clean) এবং সহজপাঠ্য (readable)
cout << "Scores: ";
for (const auto& score : scores) {
cout << score << " ";
}
cout << endl;
// এলিমেন্টগুলোকে মডিফাই (Modifying) করা — এক্ষেত্রে (const ছাড়া) auto& ব্যবহার করুন
for (auto& score : scores) {
score += 5; // সবাইকে 5 করে বাড়িয়ে দেওয়া বা curve up
}
cout << "Curved: ";
for (const auto& score : scores) {
cout << score << " ";
}
cout << endl;
// এটি স্ট্রিংগুলোর বা strings-এর সাথেও দারুণ কাজ করে (Works)
vector<string> names = {"Alice", "Bob", "Carol"};
for (const auto& name : names) {
cout << "Hello, " << name << "!" << endl;
}
return 0;
}
Output
Scores: 95 87 92 78 100
Curved: 100 92 97 83 105
Hello, Alice!
Hello, Bob!
Hello, Carol!
Note: যেকোনো রেঞ্জ-বেসড ফর লুপের (range-based for) ক্ষেত্রে সর্বদা & ব্যবহার করুন: যেমন for (auto& x : vec)& ছাড়া এটি আপনাকে প্রতিটি এলিমেন্টের শুধুমাত্র একটি অনুলিপি বা কপি (copy) প্রদান করে — এক্ষেত্রে আপনি যদি এর কোনো কিছু পরিবর্তন (modifications) করেন তবে তা আপনার মূল ফাইলের (original) ওপর কোনো প্রভাব ফেলবে না, এবং প্রতিটি এলিমেন্টকে (every element) কপি করতে গিয়ে আপনাকে শুধু শুধু অতিরিক্ত একটি পারফরম্যান্স খরচও (performance cost) দিতে হবে। তাই যখন আপনাকে শুধুমাত্র ডেটা পড়ার (read) প্রয়োজন হয় তখন const auto& ব্যবহার করুন এবং যখন আপনাকে ডেটা পরিবর্তন করার বা মডিফাইয়ের (modify) প্রয়োজন হয় তখন auto& ব্যবহার করুন।

সি++১৭ (C++17): লুপগুলোর ক্ষেত্রে স্ট্রাকচারড বাইন্ডিং (Structured Bindings in Loops)

যেকোনো map-এর ওপর ইটারেট (iterating) করে চলার সময় এর প্রতিটি এলিমেন্টই (element) মূলত .first (কি বা key) এবং .second (ভ্যালু বা value)-এর pair বা জোড়া হিসেবে কাজ করে। সি++১৭-এর (C++17) আগে এটি লিখতে গেলে অত্যন্ত বিদঘুটে বা ক্লাঙ্কি (clunky) দেখাতো। কিন্তু এই স্ট্রাকচারড বাইন্ডিং-এর (structured bindings) সাহায্যে আপনি এখন চাইলেই ওই লুপের ঠিক হেডার বা হেডারের (loop header) মাঝেই এদের জোড়া বা পেয়ারটিকে (pair) আনপ্যাক (unpack) করতে পারেন — এবং প্রয়োজন অনুযায়ী যেকোনো নাম (naming) দিয়ে এর ওই কি (key) বা ভ্যালুগুলোকে (value) গ্রহণ করতে পারেন।

ম্যাপগুলোর (Maps) সাথে স্ট্রাকচারড বাইন্ডিং বা Structured Bindings (সি++১৭ বা C++17)

#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> ages = {
{"Alice", 30},
{"Bob", 25},
{"Carol", 28}
};
// C++17 এর আগে — বিদঘুটে বা clunky .first এবং .second
cout << "Old style:" << endl;
for (const auto& pair : ages) {
cout << " " << pair.first << " is " << pair.second << endl;
}
// C++17 এর স্ট্রাকচারড বাইন্ডিংগুলো বা structured bindings — পরিষ্কার বা clean এবং সহজপাঠ্য বা readable!
cout << "\nC++17 style:" << endl;
for (const auto& [name, age] : ages) {
cout << " " << name << " is " << age << endl;
}
// স্ট্রাকচারড বাইন্ডিংগুলোর সাহায্যে বিভিন্ন ভ্যালুগুলোকে মডিফাই (Modifying) করা
for (auto& [name, age] : ages) {
age++; // সবাইকে শুভ জন্মদিন বা happy birthday!
}
cout << "\nAfter birthdays:" << endl;
for (const auto& [name, age] : ages) {
cout << " " << name << " is now " << age << endl;
}
return 0;
}
Output
Old style:
  Alice is 30
  Bob is 25
  Carol is 28

C++17 style:
  Alice is 30
  Bob is 25
  Carol is 28

After birthdays:
  Alice is now 31
  Bob is now 26
  Carol is now 29

break এবং continue — লুপ কন্ট্রোল বা Loop Control

এই break মূলত সম্পূর্ণ লুপ (loop) থেকেই বেরিয়ে আসতে (exits) সাহায্য করে — যেমন ধরুন কোনো কনভেয়র বেল্টের (conveyor belt) জরুরি স্টপ বাটন (emergency stop) টেনে ধরা। আর continue মূলত এর বর্তমান চক্রের বা ইটারেশনের (current iteration) ওই নির্দিষ্ট অংশটিকে এড়িয়ে (skips) এর পরবর্তী (next) অংশে জাম্প (jumps) করতে সাহায্য করে — অনেকটা কোনো খারাপ জিনিসকে বেল্ট থেকে ফেলে দিয়ে (tossing) এর লাইনটিকে চালু বা moving রাখার মতো।

break এবং continue

#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numbers = {1, 2, -1, 4, 5, -1, 7, 8};
// continue — সকল নেগেটিভ নাম্বার (negative numbers) এড়িয়ে বা skip যান
cout << "Positives only: ";
for (const auto& n : numbers) {
if (n < 0) continue; // এই ইটারেশনটি বা iteration-টি এড়িয়ে যান বা skip করুন
cout << n << " ";
}
cout << endl;
// break — প্রথম নেগেটিভ বা negative নাম্বারটি এলেই থেমে (stop) যান
cout << "Until negative: ";
for (const auto& n : numbers) {
if (n < 0) break; // পুরো লুপ (loop) থেকে বের হয়ে যান বা exit করুন
cout << n << " ";
}
cout << endl;
// break-এর সাথে কোনো কিছু সার্চ (Searching) করা
vector<string> names = {"Alice", "Bob", "Carol", "Dave"};
string target = "Carol";
for (const auto& name : names) {
if (name == target) {
cout << "Found " << target << "!" << endl;
break;
}
}
return 0;
}
Output
Positives only: 1 2 4 5 7 8
Until negative: 1 2
Found Carol!
চ্যালেঞ্জ

ছোট কুইজ

for (auto x : vec) এবং for (auto& x : vec)-এর মধ্যে আসলে পার্থক্য (difference) কী?
ConditionalsArrays & Vectors