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

অপারেটর এবং এক্সপ্রেশন (Operators & Expressions)

আপনার স্টোরের সমস্ত টুল বা সরঞ্জাম — পাওয়ার টুলগুলোসহ

সি-এর টুলবক্স (C's Toolbox)

পাইথন (Python) যদি আপনাকে একটি ছোট এবং সুন্দর ছোট্ট টুলকিট (toolkit) দিয়ে থাকে, তবে সি (C) মূলত আপনাকে পুরো হার্ডওয়্যারের দোকানটিই (entire hardware store) দিয়ে দেবে। এতে আপনি এর সাধারণ পাটিগণিতের (arithmetic) এবং তুলনামূলক অপারেটরগুলো (comparison operators) তো পাবেনই, সেই সাথে এর বিটওয়াইজ অপারেটরগুলোতেও (bitwise operators) সরাসরি অ্যাক্সেস (access) পাবেন — যেগুলো মূলত এমন কিছু টুল (tools) যা আপনাকে মেমোরির (memory) যেকোনো নির্দিষ্ট বিটকে (bits) নিজের মতো করে উল্টানোর (flip) সুযোগ দেয়। ঠিক এই কারণেই সি (C) প্রোগ্রামিং ভাষাকে মূলত অপারেটিং সিস্টেম (operating systems) এবং যেকোনো এমবেডেড ডিভাইসের (embedded devices) ভাষা (language) বলা হয়ে থাকে。

চলুন এখন এর নিত্যদিনের হাতুড়ি বা হ্যামার (hammers) থেকে শুরু করে একেবারে এর পাওয়ার টুলগুলো (power tools) পর্যন্ত প্রতিটি ক্যাটাগরিকে (category) একে একে দেখে নেওয়া যাক।

অ্যারিথমেটিক বা পাটিগণিতের অপারেটরগুলো (Arithmetic Operators)

এর সাধারণ (basics) অপারেটরগুলো হলো: + (যোগ বা add), - (বিয়োগ বা subtract), * (গুণ বা multiply), / (ভাগ বা divide), এবং % (মডুলো বা modulo — অর্থাৎ ভাগের পর অবশিষ্ট বা remainderটুকু)। এগুলো ঠিক আপনার প্রত্যাশা বা চিন্তার (expect) মতোই কাজ করে, তবে এখানে একটি গুরুত্বপূর্ণ ক্যাচ (catch) বা ফ্যাক্ট রয়েছে...

অ্যারিথমেটিক (Arithmetic) — ইনটিজার বা পূর্ণসংখ্যার ভাগগুলো খেয়াল করুন (Watch the Integer Division!)

#include <stdio.h>
int main() {
int a = 17, b = 5;
printf("%d + %d = %d\n", a, b, a + b);
printf("%d - %d = %d\n", a, b, a - b);
printf("%d * %d = %d\n", a, b, a * b);
printf("%d / %d = %d\n", a, b, a / b); // সারপ্রাইজ (Surprise)!
printf("%d %% %d = %d\n", a, b, a % b);
// এর সমাধান (fix): একে ডাবল-এ (double) কাস্ট (cast) করুন
printf("%d / %d = %.2f\n", a, b, (double)a / b);
return 0;
}
Output
17 + 5 = 22
17 - 5 = 12
17 * 5 = 85
17 / 5 = 3
17 % 5 = 2
17 / 5 = 3.40
Note: ইনটিজার ডিভিশন বা পূর্ণসংখ্যার ভাগ মূলত ট্রাঙ্কেটস (truncates) করে বা কেটে দেয়! যখন এর উভয় অপারেন্ডই (operands) ইনটিজার বা পূর্ণসংখ্যা (integers) হয়, তখন / মূলত এখানকার দশমিক বা ডেসিমাল অংশটিকে (decimal part) সরাসরি ফেলে দেয় বা থ্রো (throws) করে দেয়। তাই 5 / 2 মূলত আপনাকে 2 রিটার্ন করে, 2.5 নয়। তবে আপনার যদি এখানকার দশমিক (decimal) অংশের প্রয়োজন পড়ে, তবে এর অন্তত যেকোনো একটি অপারেন্ডকে (operand) double-এ কাস্ট (cast) করে নিতে হবে: যেমন (double)5 / 2 যা আপনাকে 2.5 রিটার্ন করে।

রিলেশনাল এবং লজিকাল অপারেটর (Relational & Logical Operators)

রিলেশনাল অপারেটরগুলো (Relational operators) মূলত যেকোনো দুটি মানের বা ভ্যালুর (values) মধ্যে তুলনা (compare) করে এবং এর ফলাফল হিসেবে 1 (সত্য বা true) অথবা 0 (মিথ্যা বা false) রিটার্ন (return) করে। আর লজিকাল অপারেটরগুলো (Logical operators) মূলত এগুলোর শর্ত বা কন্ডিশনগুলোকে (conditions) একত্রিত (combine) করে। মনে রাখবেন — সি (C)-তে ডিফল্টভাবে (by default) কোনো True বা False কিওয়ার্ড (keywords) থাকে না, এখানে শুধু 1 এবং 0 থাকে।

তুলনা এবং লজিক (Comparisons and Logic)

#include <stdio.h>
int main() {
int x = 10, y = 20;
// রিলেশনাল অপারেটরগুলো (Relational operators)
printf("%d == %d : %d\n", x, y, x == y);
printf("%d != %d : %d\n", x, y, x != y);
printf("%d > %d : %d\n", x, y, x > y);
printf("%d <= %d : %d\n", x, y, x <= y);
// লজিকাল অপারেটরগুলো (Logical operators)
int age = 25;
int has_id = 1;
printf("Can enter: %d\n", age >= 21 && has_id);
printf("Is teen or senior: %d\n", age < 20 || age > 60);
printf("NOT has_id: %d\n", !has_id);
return 0;
}
Output
10 == 20 : 0
10 != 20 : 1
10 >  20 : 0
10 <= 20 : 1
Can enter: 1
Is teen or senior: 0
NOT has_id: 0

ইনক্রিমেন্ট এবং ডিক্রিমেন্ট (Increment & Decrement)

এই ++ এবং -- অপারেটরগুলো (operators) এর সাথে যথাক্রমে 1 যোগ (add) বা বিয়োগ (subtract) করে। কিন্তু আপনি এগুলোকে কোথায় (where) প্লেস (place) বা বসাচ্ছেন তা এখানে খুব গুরুত্বপূর্ণ (matters): যেমন ++x (প্রিফিক্স বা prefix) মূলত মান বা ভ্যালুটিকে (value) ব্যবহারের আগেই (before) ইনক্রিমেন্ট (increments) করে, যেখানে x++ (পোস্টফিক্স বা postfix) মূলত এর মান বা ভ্যালুটিকে (value) ব্যবহারের পর (then) এটিকে ইনক্রিমেন্ট (increments) করে বা বাড়ায়। এটি সি (C) প্রোগ্রামিংয়ের ইন্টারভিউগুলোর (interview) অন্যতম ক্লাসিক (classic) একটি সাধারণ প্রশ্ন।

প্রিফিক্স বনাম পোস্টফিক্স (Prefix vs Postfix)

#include <stdio.h>
int main() {
int a = 5, b = 5;
printf("a++: %d\n", a++); // ফাইভ বা 5 প্রিন্ট (Prints) করে, এবং তার পর (THEN) a সিক্স বা 6 হয়ে যায়
printf("a now: %d\n", a);
printf("++b: %d\n", ++b); // b সিক্স বা 6 হয়ে যায়, এবং তার পর (THEN) সিক্স বা 6 প্রিন্ট (prints) করে
printf("b now: %d\n", b);
return 0;
}
Output
a++: 5
a now: 6
++b: 6
b now: 6

অ্যাসাইনমেন্ট অপারেটর (Assignment Operators)

যেকোনো ভ্যারিয়েবলকে (variable) আপডেট (updating) করার শর্টহ্যান্ডগুলো (Shorthand) হলো: +=, -=, *=, /=, %=, এবং এর বিটওয়াইজ ভারিয়েন্টগুলো (bitwise variants) হলো &=, |=, ^=, <<=, >>=

কম্পাউন্ড অ্যাসাইনমেন্ট (Compound Assignment)

#include <stdio.h>
int main() {
int score = 100;
score += 50; // স্কোর (score) = স্কোর (score) + ৫০ (50)
printf("After += 50: %d\n", score);
score -= 30; // স্কোর (score) = স্কোর (score) - ৩০ (30)
printf("After -= 30: %d\n", score);
score *= 2; // স্কোর (score) = স্কোর (score) * ২ (2)
printf("After *= 2: %d\n", score);
score /= 3; // স্কোর (score) = স্কোর (score) / ৩ (3) (ইনটিজার ডিভিশন বা integer division)
printf("After /= 3: %d\n", score);
score %= 10; // স্কোর (score) = স্কোর (score) % ১০ (10)
printf("After %%= 10: %d\n", score);
return 0;
}
Output
After += 50: 150
After -= 30: 120
After *= 2:  240
After /= 3:  80
After %= 10: 0

বিটওয়াইজ অপারেটর — পাওয়ার টুলস (Bitwise Operators — The Power Tools)

এই অপারেটরগুলো (operators) মূলত এর যেকোনো একক বিটের (bits) ওপর কাজ করে — অর্থাৎ এর ওই 0 এবং 1 গুলোর (0s and 1s) ওপর কাজ করে যেগুলো দিয়ে মূলত মেমোরির (memory) যেকোনো সংখ্যা তৈরি হয়। যেকোনো সিস্টেম প্রোগ্রামিং (systems programming), এমবেডেড ডিভাইস (embedded devices) এবং পারফরম্যান্স-ক্রিটিকাল কোডগুলোর (performance-critical code) ক্ষেত্রে এগুলো অত্যন্ত গুরুত্বপূর্ণ (essential) একটি জিনিস।

  • & (AND) — এখানকার উভয় বিটকেই (bits) অবশ্যই 1 হতে হবে
  • | (OR) — এর অন্তত একটি বিটকে (bit) অবশ্যই 1 হতে হবে
  • ^ (XOR) — এখানকার এক্স্যাক্টলি (Exactly) বা ঠিক একটি বিটকেই (bit) শুধু 1 হতে হবে
  • ~ (NOT) — এর সমস্ত বিটকে (bits) উল্টে (Flip) দিন
  • << (লেফট শিফট বা left shift) — এর বিটগুলোকে বা bits-কে বাম দিকে সরান (shift) (২ বা 2 দ্বারা গুণ বা multiply করুন)
  • >> (রাইট শিফট বা right shift) — এর বিটগুলোকে বা bits-কে ডান দিকে সরান (shift) (২ বা 2 দ্বারা ভাগ বা divide করুন)

বিটওয়াইজ অপারেশনসমূহ (Bitwise Operations)

#include <stdio.h>
int main() {
unsigned char a = 0b11001010; // ডেসিমাল বা দশমিকে 202
unsigned char b = 0b10110101; // ডেসিমাল বা দশমিকে 181
printf("a & b = %d\n", a & b); // অ্যান্ড (AND)
printf("a | b = %d\n", a | b); // অর (OR)
printf("a ^ b = %d\n", a ^ b); // এক্সঅর (XOR)
printf("~a = %d\n", (unsigned char)~a); // নট (NOT)
// শিফটিং (Shifting) = 2-এর পাওয়ার (powers of 2) দ্বারা দ্রুত বা fast গুণ/ভাগ (multiply/divide) করা
int x = 5;
printf("%d << 1 = %d\n", x, x << 1); // 5 * 2 = 10
printf("%d << 3 = %d\n", x, x << 3); // 5 * 8 = 40
printf("%d >> 1 = %d\n", x, x >> 1); // 5 / 2 = 2
return 0;
}
Output
a & b  = 128
a | b  = 255
a ^ b  = 127
~a     = 53
5 << 1 = 10
5 << 3 = 40
5 >> 1 = 2
Note: অপারেটরের প্রেসিডেন্স (Operator precedence) বা অগ্রাধিকারগুলো মূলত আপনাকে যেকোনো সময় কামড় বসাতে (bite) পারে। উদাহরণস্বরূপ, x & 1 == 0 এর মান কখনোই (x & 1) == 0 নয় (not) — এটি মূলত x & (1 == 0) কারণ এই == এর প্রেসিডেন্স বা অগ্রাধিকারটি &-এর তুলনায় অনেক বেশি থাকে। তাই যখনই কোনো সন্দেহ (doubt) হবে, সবসময় ব্র্যাকেট বা প্যারেনথেসিসগুলো (parentheses) ব্যবহার করুন। এতে করে আপনার ভবিষ্যৎ সত্তা (future self) এই কাজের জন্য আপনাকে ধন্যবাদ দেবে।
চ্যালেঞ্জ

ছোট কুইজ

সি (C)-তে 7 / 2-এর মান কত হয় (যদি এখানকার উভয় অপারেন্ডই int হয়)?
Variables & Data TypesInput & Output