Difference between increment and decrement operator of Printf() function

Difference between increment and decrement operator of Printf() function

printf ফাংশনে ইনক্রিমেন্ট আর ডিক্রিমেন্ট অপারেটরের ভিন্নতা

প্রোগ্রামিং জগতের সাথে যারা পরিচিত তারা অবশ্যই ইনক্রিমেন্ট(increment) আর ডিক্রিমেন্ট(decrement) অপারেটর সম্পর্কে সবাই কম বেশি জানি। আজকের লিখাটি বিগেইনারদের জন্য একটু ট্রিকি হতে পারে। খাতা আর কলম নিয়ে বসুন এবং নিচের কোডটি একটু লক্ষ্য করুন -

#include<stdio.h>
int main()
{
int a=5;
printf("%d %d %d %d", ++a, a++, a++, ++a);
return 0;
}

যদি আপনার আউটপুট 9 7 6 9 না হয় তাহলে আপনাকে অভিনন্দন কারণ এই আর্টিকেলটি আপনার জন্যেই। আজকে আমরা জানবো কিভাবে এবং কেনো কম্পাইলার আমাদের এমন অদ্ভুত রেজাল্ট দিচ্ছে।

আজকের আর্টিকেলে ইনক্রিমেন্ট/ডিক্রিমেন্ট নিয়ে আলোচনা হবে না। যাদের প্রি এবং পোস্ট ইনক্রিমেন্ট/ডিক্রিমেন্ট নিয়ে ধারণা নেই তারা অবশ্যই আগে বেসিক ধারণা ক্লিয়ার করে তারপর এই আর্টিকেলটি পড়বেন।

ছোট্ট একটি সমস্যা দিয়েই শুরু করি।

Example 01

#include<stdio.h>
int main()
{
    int a=5;
    printf("%d %d", a++, a++);
    return 0;
}

Output

6 5

সমস্যাটিতে '++' অপারেটর কিংবা পোস্ট ইনক্রিমেন্ট ব্যবহার করা হয়েছে যেই অপারেট এর কাজ সম্পন্ন হয় right to left এ। অর্থাৎ আগে সর্বডান কিংবা right most side এ যে ভ্যারিয়েবল রয়েছে তা আগে ইনক্রিমেন্ট হবে। পোস্ট ইনক্রিমেন্টে আগে ভ্যালু স্টোর হয় তারপর ইনক্রিমেন্টে হবে। একটু লক্ষ্য করলে দেখতে পাবো সমস্যাটিতে printf ফাংশনে দুটো a++ আছে। তবে সবার ডানে যে a++ রয়েছে সেটির কাজ আগে সম্পন হবে তারপর ক্রমে বামে আসতে থাকবে।

Right most a++ এ শুরুতে 5 স্টোর হলো তারপর ইনক্রিমেন্ট হয়ে হলো 6. সেই ভ্যালু চলে গেলো পূর্বের a++ এর কাছে এবং স্টোর হলো 6. ভ্যালু ক্যালকুলেশন right to left হলেও প্রিন্ট হচ্ছে সবসময়ের মতো left to right এ। এ কারনে আউটপুট 5 6 না হয়ে হচ্ছে 6 5।

a = 5 (1).gif

এবার আসা যাক প্রি ইনক্রিমেন্টে।

Example 02

#include<stdio.h>
int main()
{
    int a=5;
    printf("%d %d", ++a, ++a);
    return 0;
}

Output

7 7

একটু কি খটকা লাগছে? দুটো ভ্যালুই কেনো 7 আসলো। ইনিশিয়াল ডিক্লায়ারেশন ছিলো 5 তা দুই করে বেড়ে গেলো? আসুন এর কনসেপ্ট এবার উদ্ধার করি।

পোস্ট ইনক্রিমেন্টে ক্যালকুলেশনের সাথে সাথে ভ্যালু স্টোর হয়ে গেলেও প্রি ইনক্রিমেন্টে আগে সবগুলো ভ্যারিয়েবলের ক্যালকুলেশন শেষ হবে তারপর স্টোর হবে। একটু কি প্যাঁচানো লাগছে? একটু সহজে বুঝার চেষ্টা করি। পোস্ট ইনক্রিমেন্টের মতো এটারও ক্যালকুলেশন শুরু হবে right most থেকে। প্রি ইনক্রিমেন্টে যেহেতু ভ্যালু আগে ইনক্রিমেন্টেট হয় তাই সবার ডানের ++a হিসেবের সময় 5 হয়ে যাবে 6। কিন্তু সেটা স্টোর হবে না। এখন a এর বর্তমান ভ্যালু হলো 6 যেটি আগের ++a এর কাছে গিয়ে সেটি ইনক্রিমেন্টে হয়ে হলো 7। আমাদের আর কোনো ইনক্রিমেন্টেট অপারেটর নেই বিধায় এখন ভ্যালু স্টোর হওয়া শুরু করবে। এবং প্রিন্ট হয়ে হলো 7 7.

এখনও বুঝতে অসুবিধা হচ্ছে? আচ্ছা একটি গল্প বলি শুনুন। সৌরভ ভার্সিটির একজন অনিয়মিত ছাত্র। ঠিক মতো পড়াশোনা করে না, ক্লাস করে না, এসাইনমেন্টও বন্ধুরগুলো কপি করে লিখে। একবার তার টিচার তিনটি প্রশ্ন এসাইনমেন্ট দিয়েছে। সাবমিটের মিনিট পঞ্চাশ আগে তার মনে পরলো যে এসাইনমেন্টগুলো করা হয়নি। সে জানেও না কি এসাইনমেন্ট দিয়েছে। তার কাছের বন্ধুর থেকে বরাবরের মতো এবারও এসাইনমেন্ট চেয়ে লিখা শুরু করলো। তখন তার কাছে মাত্র তিরিশ মিনিট বাকি ছিলো এবং দেখলো তিনটি উত্তরের মধ্যে প্রথম উত্তরটি তুলনামূলক বড় ছিলো। দ্বিতীয়টি প্রথমটির তুলনায় ছোটো কিন্তু তিন নং উত্তরটি অর্ধেক পেইজ। সে চিন্তা করলো ছোটো উত্তর গুলো আগে লিখে বড় মানে প্রথম উত্তরটি শেষে সময় পেলে লিখবে। সে ক্রমান্বয়ে তিন তারপর দুই তারপর এক লিখা শেষ করলো সময়ের আগেই। এখন জমা দেওয়ার পালা। জমা দিয়ে গিয়ে দেখলো পেইজগুলো উল্টাপাল্টা। জলদি করে একটা সিকোয়েন্সে এনে পিন করলো। তার টিচার বলে দিয়েছে উত্তরের সিকোয়েন্সে ঠিক থাকতে হবে তাই সে প্রথমে এক তারপর দুই তারপর তিন নং উত্তর রেখে জমা দিলো। একটু লক্ষ্য করুন। সৌরভ ঠিকই উত্তর লিখা শেষ থেকে শুরু করেছিলো, কিন্তু জমা দেয়ার সময় নাম্বারের ধাচ অনুযায়ী সাজিয়েই জমা দিয়েছে। ঠিক এভাবেই প্রি ইনক্রিমেন্টে শেষ থেকে কাজ শুরু করলেও আউটপুট প্রিন্টের সময় শুরু থেকেই করবে।

আরেকটি উদাহরণ লক্ষ করি আসেন।

Example 03

int a = 5 ;
printf("%d %d %d", a++, a++, ++a);

এখানে কম্পাইলার ক্যালকুলেট করবে right most ++a -> এটা সাথে সাথে a এর ভ্যালু এক ইনক্রিমেন্টে করে 6 করবে কিন্তু এই ভ্যালুটা এখনই printf ফাংশনে দিবে না। তারপর এটি চলে যাবে এর পূর্ববর্তী a++ এ -> এখানে আমরা ভ্যালু 6 পাবো, যেহেতু পোস্ট ইনক্রিমেন্ট তাই সেটি স্টোর করবে এবং ইনক্রিমেন্টে হয়ে হবে 7। পরবর্তীতে এই 7 যাবে এই অপারেটর এর বামে কিংবা left most এ। যেহেতু পোস্ট ইনক্রিমেন্টের অপারেটর তাই আগে স্টোর হবে এবং তার পরে গিয়ে ইনক্রিমেন্টেট হয়ে হবে 8।

এখন লক্ষ করুন, আমরা পোস্ট ইনক্রিমেন্টের জন্যে ভ্যালু বসিয়ে ফেলেছছি কিন্তু প্রি ইনক্রিমেন্টে এখনও ভ্যালু রাখিনি। আমরা জানি যে প্রি ইনক্রিমেন্টে ভ্যালু সকল ক্যালকুলেশনের শেষে স্টোর হবে। আমাদের সব ক্যালকুলেশন শেষ এবং লেটেস্ট ইনক্রিমেন্টেট ভ্যালু পেয়েছি 8। ++a তে গিয়ে এখন 8 স্টোর হবে। এখন আউটপুটের পালা। printf ফাংশনটি যেহেতু letf to right করে থাকে থাকে তাই আউটপুট পাবো 7 6 8.

আশা করি সবাই বুঝে গেছেন প্রি এবং পোস্ট ইনক্রিমেন্ট printf ফাংশনে কিভাবে কাজ করে। তবে অতি প্রয়োজনীয় না হলে gcc complier এর printf ফাংশনে একের অধিক এই অপারেটর দুটো ব্যবহার না করাই শ্রেয় হবে।

এখন আপনাদের কাজ থাকবে যে একদম শুরুতে আমরা যে উদাহরণ দিয়েছিলাম সেটার আউটপুট উপরোক্ত কনসেপ্ট দিয়ে হচ্ছে কিনা বের করা। যদি আপনি ইনক্রিমেন্টে পারেন একইভাবে ডিক্রিমেন্ট অপারেট নিয়েও কাজ করতে পারবেন। প্র্যাকটিসের জন্যে কিছু উদাহরণ দিয়ে দিচ্ছি। উত্তর বের করে কমেন্ট বক্সে জানাবেন। আর কোনো প্রকার অসুবিধা থাকলে আমাকে মেইল করবেন। ধন্যবাদ।

Home Work 01

#include<stdio.h>
int main()
{
    int a=5;
    printf("%d %d", --a, --a);
    return 0;
}

Home Work 02

#include<stdio.h>
int main()
{
    int a=5;
    printf("%d %d", a--, a--);
    return 0;
}

Home Work 03

#include<stdio.h>
int main()
{
    int a=5;
    printf("%d %d %d %d", --a, a--, a--, --a);
    return 0;
}

Home Work 04

#include<stdio.h>
int main()
{
    int a=5;
    printf("%d %d %d %d %d %d %d %d %d", ++a, a++, a++, ++a, a--, ++a, a--, --a, a++);
    return 0;
}

N.B:

  • প্রি এবং পোস্ট ইনক্রিমেন্ট আর ডিক্রিমেন্টের ভ্যালু ক্যালকুলেশন শুরু হবে Right Most থেকে
  • পোস্ট ইনক্রিমেন্ট কিংবা ডিক্রিমেন্টে ভ্যালু ক্যালকুলেশনের সাথে সাথে স্টোর হওয়া শুরু করবে
  • প্রি ইনক্রিমেন্ট কিংবা ডিক্রিমেন্টে সবগুলো অপারেটরের ভ্যালু আগে ক্যালকুলেশন হয়ে সবার শেষে স্টোর হবে
  • কিন্তু প্রিন্ট করা শুরু করবে Left Most format specifiers থেকে