লিনিয়ার বা সিকোয়েন্সিয়াল সার্চ

লিনিয়ার বা সিকোয়েন্সিয়াল সার্চ একেবারে মৌলিক একটি সার্চ এলগোরিদম। নাম অনুযায়ীই এটি একটি ডেটা স্ট্রাকচারের উপাদানগুলিকে পর্যায় ক্রমে খুঁজে খুঁজে কাংক্ষিত উপাদানটি খুজে বের করে। অবিন্যস্ত ডেটা বা এমন ডেটা যা কোন নির্দিষ্ট ক্রমে সজ্জিত নয়, তার ক্ষেত্রে এটিই একমাত্র সার্চ টেকনিক তবে এটি বেশ সময় সাপেক্ষ।



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

আমাদের পরিচিত ডেটা স্ট্রাকচার array দিয়েই আমরা উদাহরণটি দিই। ধরা যাক, ১২ টি ভিন্ন সংখ্যা একটি array তে রাখা আছে। আমরা এই array তে লিনিয়ার সার্চ চালিয়ে দেখবো যে এখানে 25 সংখ্যাটি আছে কি না। ধরি, এই array তে সংখ্যাটি নেই। সেই ক্ষেত্রে 0 নম্বর ইন্ডেক্স থেকে 11 নম্বর ইন্ডেক্স পর্যন্ত সার্চ চলবে।



আবার ধরা যাক একটি array তে ১৫ টি ইন্ডেক্স এ 1-15 পর্যন্ত সংখ্যাগুলো আছে। আমাদের সেখান থেকে 9 কে খুজে বের করতে হবে। এই ক্ষেত্রেও আমরা 0 নম্বর ইন্ডেক্স থেকে খোজা শুরু করবো, এবং 8 নম্বর ইন্ডেক্স পর্যন্ত সার্চ চালিয়ে গেলে আমরা আমাদের কাংক্ষিত সংখ্যা 9 খুজে পাবো।


আমাদের কাজের ধাপ হবেঃ

১. 0 ইন্ডেক্স এ খুজে দেখা হবে।
২. যদি কাংক্ষিত সংখ্যা খুজে না পাওয়া যায় এবং এটিই শেষ ডেটা উপাদান না হয় তাহলে ইন্ডেক্স সংখ্যা ১ বৃদ্ধি পাবে এবং আবার ১ নং ধাপে ফেরত যাওয়া হবে। এটিই শেষ ডেটা উপাদান হলে সার্চ থেমে যাবে এবং খুজে পাওয়া যায় নি এমন মেসেজ দেওয়া হবে। যদি কাংক্ষিত সংখ্যা খুজে পাওয়া যায় তাহলেও সার্চ থেমে যাবে এবং খুজে পাওয়া গিয়েছে এমন মেসেজ দেওয়া হবে।

এইবার একটি সহজ কোড দেখি। ধরি array[20] একটি array যেখানে ২০ টি সংখ্যা আছে এবং আমাদের খুজে বের করতে হবে যে কত নম্বর ইন্ডেক্সে 75 সংখ্যাটি আছে।

#include<stdio.h>

int main()
{
    int i,array[20] = {2,3,5,6,33,45,6,34,57,55,75,89,4,6,7,86,54,32,99,78};

    for (i=0; i<20; i++)
    {
        if (array[i]==75)
        {
            printf("Found at index %d", i);
            break;
        }
     }
     if (i==20)
         printf("Not found in any index.");

    return 0;
}

একটি বাক্য থেকে শব্দ গণনা

ধরা যাক আমাদেরকে বলা হল যে, একটা ইংরেজি বাক্য দেওয়া আছে। আমাদের গুনে বের করতে হবে যে বাক্যটিতে কয়টি শব্দ আছে। আমরা চোখ দিয়ে তাকিয়ে শব্দ গুনে ফেলতে পারবো, কোন সমস্যা নয়। কিন্তু আমাদের যদি একটি প্রোগ্রাম লিখতে হয় এই গোনার কাজটি করার জন্য, তখন আমরা কি করব?

প্রথমেই আসবে ইনপুট এর ব্যাপার টা। বাক্যটাকে প্রথমে আমরা ইনপুট নিবো। আর যেহেতু একটি বাক্য অনেকগুলো ক্যারেকটার এর সমন্বয় তাই আমাদের চিন্তা করতে হবে স্ট্রিং ইনপুট নিয়ে। বাক্যটাকে আমরা একটি স্ট্রিং হিসেবেই ইনপুট নিবো।

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

লিনিয়ার সার্চের মতই আমরা স্ট্রিং এর প্রথম ইন্ডেক্স থেকে খোজা শুরু করবো এবং শেষের নাল টার্মিনেটর ধারী ইন্ডেক্স পর্যন্ত খুঁজবো। এখন প্রশ্ন হল, আমরা কোন বৈশিষ্ট্য টা ধরে খুজবো? কিসের উপর ভিত্তি করে খুজলে আমরা শব্দের সঠিক সংখ্যা খুজে পাবো? আসুন আমরা একটা উদাহরণ দিই। ধরি,

I love you.

হল আমাদের ইংরেজি বাক্য। আমরা জানি বাক্যের ২ টি শব্দের মধ্যে একটি ফাকা স্থান বা blank স্পেস থাকে। কাজেই আমরা যদি ফাকা স্থানের সংখ্যা বের করি তাহলে শব্দ হিসাব করাটা কিছুটা সহজ হবে। যেমন, উপরের উদাহরণ এ ২ কি ফাকা স্থান আছে। আর, ব্যাকরণগত ভাবে সঠিক যে কোন বাক্যের শেষে একটি ফুলস্টপ থাকবে এবং তার আগে একটি শব্দ থাকবে। তাই স্পেস সংখ্যার সাথে ১ যোগ করলেই আমরা পেয়ে যাবো শব্দ সংখ্যা।

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

আমি একটি শর্ত সাজেস্ট করি।

১. আমরা একেবারে শুরুর ইন্ডেক্স থেকে গননা শুরু করবো না। আমরা ১ নম্বর ইন্ডেক্স থেকে গননা শুরু করবো।
২. আমরা তিনটা জিনিসের দিকে নজর রাখবো। স্পেস, স্পেশাল ক্যারেকটার আর নাল টার্মিনেটর।

৩. এদের যে কোন একটাকে খুঁজে পেলে চেক করে দেখবো যে তার আগের ইন্ডেক্সে একটি এলফাবেট বা নাম্বার আছে কি না। যদি এলফাবেট থাকে তাহলে আমরা ধরে নিবো যে একটা শব্দ (হিসাবে সুবিধার জন্য আমরা ধরে নিচ্ছি যে সংখ্যা বা সংখ্যাযুক্ত শব্দও শব্দ) আমরা পেয়ে গেছি। আর যদি তা না হয় তাহলে আমরা পরবর্তি ইন্ডেক্সে সার্চ চালিয়ে যাবো।

কাজেই আমাদের কোড এর গঠন হবে,

#include<stdio.h>
#include<ctype.h>

int main()
{
    char str[128],  ch; /* স্ট্রিং ধারণের জন্য array */
    int i, word=0;

    /* ইনপুট অংশ শুরু */
    for (i =0;;)
    {
        ch=getchar();
        if (ch=='\n')
        {
            str[i]='\0';
            break;
         }
         str[i++]=ch;
    }
    /* ইনপুট অংশ শেষ */

    /* সার্চ শুরু */
    for (i =1; ; i++)
    {
        if (str[i]==' '||ispunct(str[i])||str[i]=='\0') /* স্পেস, স্পেশাল ক্যারেকটার ও নাল টার্মিনেটর চেক */
        {
            if (isalnum(str[i-1])) /* আগের ক্যারেকটার টি এলফাবেট বা ডিজিট কি না সেটা চেক */
            word++;

            if (str[i]=='\0')
            break;
        }
    }
    printf("Number of words = %d", word);

    return 0;
}

দেখুন তো আপনারা চিন্তা করে অন্য একটি উপায় বের করতে পারেন কি না!!!

মৌলিক সংখ্যা : সংখ্যার মৌলিকতা পরীক্ষা

ড্রাফট পোস্টঃ


প্রাইম নাম্বার হল তারা যারা কেবল ১ এবং সেই নাম্বার দ্বারা নিঃশেষে বিভাজ্য। সহজ ও সুন্দর সংগা।



কাজেই আসো আমরা একটা নাম্বার প্রাইম কি না তা বের করার যৌক্তিক পদক্ষেপ গুলো নির্ধারণ করি।

ধারনা ১:

আমরা সংখ্যাটিকে প্রথমে ২ দিয়ে ভাগ করা শুরু করতে পারি। এরপর ৩, তারপর ৪, এভাবে সেই সংখ্যাটির আগ পর্যন্ত সকল সংখ্যা দ্বারা ভাগ করে দেখতে পারি যে কোন ভাগ শেষ আসে কি না। যেহেতু ১ দ্বারা সকল সংখ্যা বিভাজ্য এবং যেকোন সংখ্যাই সেই সংখ্যা দ্বারা বিভাজ্য তাই আমরা ২ থেকে শুরু করে সংখ্যাটির আগের সংখ্যা দ্বারা ভাগ করে দেখতে পারি।

কাজেই আমাদের ইনপুট নাম্বার যদি হয় n তাহলে আমরা 2 থেকে শুরু করে n-1 পর্যন্ত ভাগ করব। এই জন্য আমাদের for স্টেটমেন্ট হবে:

for (i =2; i <n;i++)
{
    flag=1;
    if(n%i==0)
    {
        flag=0;
        break;
    }
}

এরপরে আমরা খুব সহজেই flag এর ভ্যালু চেক করে বলতে পারব যে সংখ্যাটি প্রাইম কি না। কারণ আমরা প্রথমেই ধরে নিয়েছি যে flag এর ভ্যালু  ১ এবং সংখ্যাটি i এক কোন মান দ্বারা বিভাজ্য না হলে flag এর মান ১ ই থাকবে।

এই ধারনা দ্বারা ১ থেকে ৩৫০০০০ এর মধ্যেকার সকল প্রাইম নাম্বার (২৯৯৭৭ টি) বের করতে সময় লেগেছে ১১.৮৬ সেকেন্ড। (সময় নির্ধারণঃ ideone)

ধারণা ২:

আমরা ধারণা ১ কে একটু ঘষামাজা করি।
১০/১০=১, ১০/৫=২;
৮/৮= ১, ৮/৪=২;
..........................
n/n =1, n/(n/2)=2;

তাই কোন সংখ্যা তার অর্ধেকের বেশি মানের কোন সংখ্যা দ্বারা নিঃশেষে বিভাজ্য হতে পারে না।

তাই সেই সংখ্যার অর্ধেকের বেশি মানের কোন সংখ্যা দ্বারা তাকে ভাগ করা অর্থহীন।

কাজেই আমরা ২ দ্বারা ভাগ করা শুরু করব এবং সংখ্যাটির অর্ধেক মানের সংখ্যা দ্বারা ভাগ করেই থেমে যাবো। আমাদের for স্টেটমেন্ট হবে:

for(i =2; i <=n/2; i++)
{
    flag =1;
    if(n%i==0)
    {
        flag=0;
        break;
    }
}

ধারণা ২ তে আমাদের ভাগের কাজ হবে ধারণা ১ এর প্রায় অর্ধেক। এই যুক্তি ব্যবহার করে ১-৩৫০০০০ এর মধ্যেকার সব প্রাইম নাম্বার (২৯৯৭৭ টি) বের করতে সময় লেগেছে ৫.৯৪ সেকেন্ড। (সময় নির্ধারণঃ ideone)

ধারণা ৩:

আমরা ধারনা ২ কে আরো একটু স্লিম করার চেষ্টা করি। কেমন?

* সংগা অনুসারে ২ বাদে আর কোন জোড় প্রাইম নাম্বার থাকা সম্ভব না।
* একটি জোড় সংখ্যা সব সময়ই ২ দ্বারা বিভাজ্য
* একটি জোড় ও একটি বিজোড় সংখ্যার গুনফল সব সময়ই একটি জোড় সংখ্যা।

কাজেই কোন সংখ্যা যদি ২ দ্বারা বিভাজ্য না হয় তাহলে তাকে কোন জোড় সংখ্যা দ্বারা ভাগ করে দেখা অর্থহীন।

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

কাজেই আমাদের লজিক হবে:


flag=1;
if (n==2)
    flag=1;
else if (n%2==0)
    flag=0;
else
    for (i = 3; i <=n/2; i += 2)
    {
        if(n%i==0)
        {
            flag=0;
            break;
        }
    }

ধারণা ৩ এ ভাগের কাজ হবে ধারণা ২ এর অর্ধেক। এই ধারনা ব্যবহার করে ১-৩৫০০০০ পর্যন্ত সব প্রাইম নাম্বার (২৯৯৭৭ টি) বের করতে সময় লেগেছে ২.৯৮ সেকেন্ড। (সময় নির্ধারণঃ ideone)

ধারণা ৪:

ইউক্লিড এর প্রস্তাবনা অনুসারে, যে কোন পূর্ণসংখ্যা হয় প্রাইম অথবা তার থেকে ছোট দুই বা ততোধিক প্রাইমের গুণফল। অর্থাৎ, যেকোন সংখ্যা তার চেয়ে ছোট একটি প্রাইম দ্বারা বিভাজ্য হবে যদি সেটি নিজে প্রাইম না হয়।

এখন একটা মজার জিনিস দেখি। ধরা যাক, ১০০ সংখ্যাটি প্রাইম কি না তা আমরা বের করবো। কাজেই ১০০ থেকে ছোট কোন প্রাইম দ্বারা যদি এটি বিভাজ্য না হয় তাহলেই এটি প্রাইম হবে। সবচে ছোট প্রাইম ২। ১০০/২=৫০। ৫০ এর কাছাকাছি প্রাইম হচ্ছে ৪৭। তাই ২ থেকে ৪৭ পর্যন্ত সংখ্যা দ্বারা যদি ১০০ বিভাজ্য না হয় তাহলেই ১০০ প্রাইম।

মজার জিনিসটা হচ্ছে, কোন সংখ্যা যদি প্রাইম না হয় তবে তা তার বর্গমূলের সমান বা তার চেয়ে ছোট কোন না কোন প্রাইম দ্বারা বিভাজ্য। আলোচ্চ্য ১০০ এর ক্ষেত্রে, ১০০ এর বর্গমূল ১০। তাই ২ থেকে ১০ এর মধ্যে কোন সংখ্যা দ্বারা যদি এটি বিভাজ্য না হয় তাহলেই এটি প্রাইম।

১০০ এর কাছাকাছি প্রাইমটি হচ্ছে ৯৭। ২, ৩, ৫, ৭  এই চারটি প্রাইমের কোনটি দ্বারাই ৯৭ বিভাজ্য নয়।

কাজেই,
আমরা যদি কোন সংখ্যার বর্গমূল বের করি এবং ২ থেকে শুরু করে সেই বর্গমূল পর্যন্ত সবগুলো সংখ্যা দিয়ে প্রদত্ত সংখ্যাটিকে ভাগ করে দেখি যে ভাগশেষ শূন্য নয়, তবেই সেটি প্রাইম নম্বর।

আমরা এখন ধারণা ৩ এর সাথে এই ধারণাটা যুক্ত করবো।

অর্থাৎ,


if (n==2)
    flag=1;
else if (n%2==0)
    flag=0;
else
{
    flag=1;
    m= (int) sqrt( (double) n);
    for (i = 3; i <=m; i+=2)
    {
        if (n%i==0)
        {
            flag=0;
            break;
        }
    }
}

এখন flag এর ভ্যালু চেক করলেই বোঝা যাবে যে n প্রাইম কি না।

এই ক্ষেত্রে সময় ধারনা ৩ এর চেয়েও কম লাগবে। এবং সেই কমটাও অনেক অনেক কম।

ধারণা ৪ ব্যবহার করে ১-৩৫০০০০ পর্যন্ত সবগুলো প্রাইম (২৯৯৭৭ টি) বের করতে সময় লেগেছে ০.০২ সেকেন্ড। (সময় নির্ধারণঃ ideone)

কারো ইচ্ছা থাকলে এই ধারণা ৪ টি ব্যবহার করে ১০০০০০ পর্যন্ত যতগুলো প্রাইম নম্বর আছে তা বের করে দেখতে পারো যে কোন ধারণায় কতটা সময় লাগে আউটপুট আসতে।

C কিওয়র্ড সমূহ : C Keywords

প্রোগ্রামিং ল্যাংগুয়েজ এর ক্ষেত্রে কিওয়র্ড হচ্ছে এমন কিছু word বা শব্দ যাদের অর্থ ঐ প্রোগ্রামিং ল্যাংগুয়েজ এ নির্দিষ্ট। এরা নির্দিষ্ট কিছু কাজ সম্পাদন করে থাকে যা ঐ ভাষার স্ট্যান্ডার্ড নিয়ম অনুযায়ী পূর্ব নির্ধারিত। ঐ সব কাজ ছাড়া এদেরকে আর অন্য কোন স্থানে ব্যবহার করা যায় না। কোন ইডেন্টিফায়ার (ভ্যারিয়েবল, ফাংশন ইত্যাদির নাম) হিসেবে এদেরকে ব্যবহার করা যায় না।

মোট কথা, কিওয়র্ড হল কোন ভাষার নির্দিষ্ট কিছু শব্দ যাদের কাজ ঐ ভাষার ব্যাকরণ অনুযায়ী পূর্ব নির্ধারিত এবং যারা অপরিবর্তনীয়।



ANSI স্ট্যান্ডার্ড অনুযায়ী C ভাষায় ৩২ টি কিওয়র্ড আছে। এই ৩২ টি কিওয়র্ড ও এদের ব্যবহারের ব্যাকরণ নিয়ে ANSI C ভাষাটি গঠিত। ৩২ টি কিওয়র্ড হলঃ

auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int, long, register, return, short, signed, sizeof, static, struct, switch, typedef, union, unsigned, void, volatile, while

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

  • প্রোগ্রামের প্রবাহ নিয়ন্ত্রক (flow control): এই কিওয়র্ডগুলো কোন প্রোগ্রামে কোড এক্সেকিউশনের ধারা ও ধারাবাহিকতা নিয়ন্ত্রন করে। এদেরকে আবার তিনটি উপশ্রেণী তে বিভক্ত করা যায়ঃ


            1. ব্রাঞ্চিং কিওয়র্ডঃ এরা হচ্ছে C এর মাল্টিপল সিলেকশন বা বহুমুখী পথ নির্বাচন সম্পর্কিত কিওয়র্ড। এরা নির্দিষ্ট শর্তের উপর নির্ভর করে কোন কোড এক্সেকিউট হবে, আর কোন কোড এক্সেকিউট হবে না, সেটা নির্ধারণ করে। এরা হলঃ if, else, switch, case, break, default

              2. লুপিং কিওয়র্ডঃ এরা হচ্ছে C এর পুনরাবৃত্তকরন বা reparation কিওয়র্ড। এরা C এর বিভিন্ন কোড সেগমেন্টকে নির্দিষ্ট শর্ত সাপেক্ষে বারবার এক্সেকিউট করতে সাহায্য করে। অর্থাৎ, এই কোডগুলো লুপ তৈরীতে সহায়তা করে থাকে। এরা হলঃ for, while, do, break, continue

              3. জাম্প কিওয়র্ডঃ এরা প্রোগ্রামের এক স্থান থেকে অন্য স্থানে প্রোগ্রাম এক্সেকিউশনের তাৎক্ষণিক স্থানান্তর ঘটায়। এই জন্যেই এদেরকে জাম্প কিওয়র্ড বলা হচ্ছে। এরা হলঃ return, goto


  • ডেটা টাইপ সম্পর্কিতঃ C ডেটা টাইপ সমূহ প্রয়োগ ও তাদের রূপান্তরকরণ সম্পর্কিত কাজ এই কিওয়র্ডগুলোর সহায়তায় সম্পন্ন হয়। এদেরকে ৬ টি উপশ্রেণী তে বিভক্ত করা হয়েছেঃ


              1. মৌলিক ডেটা টাইপ সমূহঃ C এর পূর্ব নির্ধারিত ৫ টি ডেটা টাইপ ব্যবহারের জন্য এই ৫ টি কিওয়র্ড ব্যবহার করা হয়। এরা হলঃ

char, int, float, double, void

              2. টাইপ লিমিট মডিফায়ার সমূহঃ এরা মৌলিক ডেটা টাইপ সমূহের ধারণক্ষমতায় কিছু পরিবর্তন আনে। এরা হচ্ছে,

short, long, signed, unsigned

              3. স্টোরেজ ক্লাস স্পেসিফায়ারঃ এরা বিভিন্ন ডেটা টাইপের ডেটা সম্বলিত ভ্যারিয়েবল সমূহ মেশিনের কোন ধরনের মেমরিতে জমা থাকবে সেই বিষয়ক নির্দেশনা দান করে। এদের ব্যবহার নিত্যনৈমিত্তিক না হলেও, দ্রুতগতির ও স্বল্প মেমরী ব্যবহারকারী প্রোগ্রাম তৈরীতে এদের ব্যবহার অপরিহার্য। এরা হলঃ

auto, extern, register, static

              4. এক্সেস মডিফায়ারঃ কোন ডেটার পরিবর্তন কিভাবে হবে বা আদৌ হবে কি না সেই সম্পর্কিত নির্দেশনা এরা দিয়ে থাকে। এদের ব্যবহারও মূলত অভিজ্ঞ প্রোগ্রামারদের হাতেই হয়ে থাকে। এরা হলঃ

const, volatile

              5. স্ট্রাকচার সম্পর্কিতঃ C ডেটা স্ট্রাকচার সম্পর্কিত কিওয়র্ড। এরা হলঃ

struct, union

              6. ইউজার ডিফাইন্ড ডেটা টাইপ সম্পর্কিতঃ এরা বিভিন্ন ইউজার ডিফাইন্ড ও এডভান্সড ডেটা টাইপ তৈরিকরণে সাহায্য করে। এরা হলঃ

typedef, enum


  • অপারেটঃ একটি মাত্র অপারেটর ই কিওয়র্ড হিসেবে বিদ্যমান। এটি কোন ডেটা টাইপ বা ভ্যারিয়েবল (যে কোন ধরণের) এর আকার বাইট (Byte) এককে হিসাব করে ব্যবহারকারী কে জানায়। এটি হলঃ


sizeof

সবগুলো কিওয়র্ডের আলাদা আলাদা সংক্ষিপ্ত কাজ ও ব্যবহার এর জন্য এখানে দেখতে পারেন।

তবে এদের পূর্ণাঙ্গ ব্যবহার কেবলমাত্র এদের নিয়মিত প্রয়োগের মাধ্যমেই শেখা সম্ভব, মুখস্থ করে নয়।

C এক্সপ্রেশন : Expression

এক্সপ্রেশন শব্দের অর্থ অভিব্যক্তি। এমন কিছু আচার আচরণ, ইশারা ইঙ্গিত, কথাবার্তা, শব্দ, মুখভঙ্গি যা আমাদের মনের একটি নির্দিষ্ট ভাব প্রকাশ করে তাই হচ্ছে অভিব্যক্তি। অভিব্যক্তি দ্বারা ভাব প্রকাশ করা হয়, অভিব্যক্তিকে সব সময়ই অর্থবহ হতে হয়।

C এক্সপ্রেশন সমূহও অনেকটা তেমনই। C ভাষায় এক্সপ্রেশন হচ্ছে অপারেটর ও অপার‍্যান্ড এর সমন্বয়ে তৈরী কোড সেগমেন্ট যার একটি নির্দিষ্ট চুড়ান্ত মান আছে। অর্থাৎ ঐ কোড সেগমেন্টকে এক্সেকিউট করলে, অপারেটর দের কাজ শেষ হবার পরে ১ টি মাত্র চুড়ান্ত মান পাওয়া যাবে। এই চুড়ান্ত মান গাণিতিক বা সংখ্যা মান হতে পারে, আবার যৌক্তিক বা লজিকার মান (সত্য বা মিথ্যা; True বা False) ও হতে পারে।

মোট কথা হল, এক্সপ্রেশন হচ্ছে এমন একটি কোড সমন্বয় যার একটি মান আছে। যেমন, ধরা যাক a, b ও c তিনটি ইন্টিজার ভ্যারিয়েবল। নিচের এসাইনমেন্ট স্টেটমেন্টটি খেয়াল করা যাক,

a= b+c;

এখানে এসাইনমেন্ট অপারেটর এর বাম পাশে আছে a এবং ডান পাশে আছে কোড সেগমেন্ট b+c। b+c এর অর্থ হচ্ছে b ও c তে জমা থাকা ভ্যালুর যোগফল। অর্থাৎ,  b+c এর একটি চূড়ান্ত মান আছে। তাই b+c অংশটি হচ্ছে একটি এক্সপ্রেশন।

এক্সপ্রেশন প্রায় সব সময়ই অপারেটর ও অপার‍্যান্ড (ভ্যারিয়েবল, কনস্ট্যান্ট ইত্যাদি) এর সমন্বয়ে গঠিত। এবং এক্সপ্রেশন এর সব সময়ই একটি লজিকাল বা যৌক্তিক মান থাকে। চুড়ান্ত মানের উপর ভিত্তি করে তার যৌক্তিক মান হয় সত্য অথবা মিথ্যা হয়।

C তে কোন বুলিয়ান (Boolean) True বা False নেই। কিন্তু অন্য একটি উপায়ে C তে সত্য বা মিথ্যা নিরূপন করা যায়। যখন কোন এক্সপ্রেশনের চুড়ান্ত সংখ্যা মান শূন্য (0) তখন সেই এক্সপ্রেশনটি মিথ্যা, অর্থাৎ লজিকাল মান হল False। যে কোন অশূন্য সংখ্যা মানের জন্য কোন এক্সপ্রেশন সত্য, অর্থাৎ লজিকালি True।
উল্টোভাবে বলতে গেলে, C ভাষায় সকল মিথ্যা এক্সপ্রেশন এর সংখ্যা মান 0 আর সত্য এক্সপ্রেশন এর মান অশূন্য (সাধারণত 1)।

মনে রাখতে হবে যে, অশূন্য মানের সকল এক্সপ্রেশন ই সত্য, তবে সাধারণত সত্য এক্সপ্রেশন এর মানকে  1 দ্বারা প্রকাশ করা হয়। এর মানে এই নয় যে, কেবল 1 ই সত্য বা True। বস্তুত কোন এক্সপ্রেশন এর মান শূন্য না হলেই তা সত্য।

এবার বলেন দেখি নিচের কোডের আউটপুট কত?

#include<stdio.h>

int main()
{
    int a, b, c, d;
    c=1;
    d=10;

    a= c>d;
    b= d<c;

    printf("%d %d", a, b);

return 0;
}

অপারেটর ও অপার‍্যান্ড এর উপর ভিত্তি করে এক্সপ্রেশন অনেক ধরনের হতে পারে। যেমন,

গাণিতিক বা Arithmetic অপারেটর কোন এক্সপ্রেশন এ থাকলে তাকে গাণিতিক বা arithmetic এক্সপ্রেশন বলে। আবার কোন গাণিতিক এক্সপ্রেশনে উপস্থিত অপার‍্যান্ড এর ধরন এর উপর ভিত্তি করে,
ইন্টিজার এক্সপ্রেশন,
ফ্লোটিং পয়েন্ট বা রিয়েল এক্সপ্রেশন
এবং মিশ্র বা মিক্সড এক্সপ্রেশন এই তিন ভাগে ভাগ করা যায়।

লজিকাল অপারেটর এর এক্সপ্রেশন হচ্ছে লজিকাল এক্সপ্রেশন আবার, কন্ডিশনাল অপারেটর সম্বলিত এক্সপ্রেশনকে কন্ডিশনাল এক্সপ্রেশন বলে।

এরকম আরো অনেক ধরনের এক্সপ্রেশন আছে।

C ভাষায় এক্সপ্রেশন খুব গুরুত্বপূর্ণ ভূমিকা পালন করে। কারণ C ভাষায় অনেক ধরনের অপারেটর আছে এবং বেশির ভাগ নির্দেশনাই এক্সপ্রেশন আকারে প্রকাশ করা হয়।

C এর শুরুটা কিভাবে ?


C একটি অত্যন্ত জনপ্রিয় প্রোগ্রামিং ল্যাংগুয়েজ এর নাম। আর প্রোগ্রামিং ল্যাংগুয়েজ হল যা দিয়ে কম্পিউটার প্রোগ্রাম তৈরি করা হয়। C জনপ্রিয় হবার কারণ হচ্ছে এটি একটি মিড লেভেল, প্রোসিডিউরাল,  স্ট্রাকচার্ড, ও মেশিন ইন্ডিপেন্ডেন্ট ভাষা। এই বিশেষণ গুলোর মানে কি সেটা আস্তে আস্তে পরিষ্কার হবে। যিনি এই প্রোগ্রামিং ভাষা তৈরি করেছেন তার নাম ডেনিস রিচি। সি ল্যাঙ্গুয়েজ তৈরি হয়েছিল ইউনিক্স অপারেটিং সিস্টেম ডেভেলপমেন্ট করার জন্য।


সংক্ষিপ্ত ইতিহাস


সব আধুনিক প্রোগ্রামিং ভাষাগুলির মূল ALGOL।  এটা ১৯৬০ সাল এ তৈরি।  ALGOL প্রথম স্ট্রাকচার প্রোগ্রামিং এর ধারণা দেয়।

১৯৬৭ এর দিকে মার্টিন রিচার্ডস BCPL (Basic Combined Programming Language) তৈরি করেন। ১৯৭০ সালে, যুক্তরাষ্ট্রের বেল গবেষণাগারে বিজ্ঞানী কেন টমসন তৈরি করেন B নামক একটি প্রোগ্রামিং ভাষা। এটি ছিল পূর্বের BCPL-এর একটি উন্নত সংস্করণ। B দিয়েই UNIX অপারেটিং সিস্টেম প্রথমে তৈরি হয়েছিল বেল গবেষণাগারে। BCPL এবং B উভয়েই টাইপবিহীন একটি প্রোগ্রামিং ভাষা ছিল।

১৯৭২ সালে, ডেনিস রিচি বেল গবেষণাগারে  ALGOL, B এবং BCPL অনুসরণ করেন এবং নিজে থেকে আরো কিছু কৌশল ব্যবহার করে তৈরি করেন "সি" (C) ল্যাঙ্গুয়েজ। মূলত B-এর সীমাবদ্ধতা গুলো দূর করার উদ্দেশ্যেই "সি" এর উৎপত্তি। এর পর UNIX অপারেটিং সিস্টেমকে C দ্বারা ডেভেলপ করা হয়। UNIX আজকের সর্বাধিক জনপ্রিয় নেটওয়ার্ক অপারেটিং সিস্টেম।

৭০ এবং ৮০ দশকের দিকে C এর জনপ্রিয়তা বাড়ার সাথে সাথে এর অনেকগুলো ভার্সন তৈরি হয়। ১৯৮৩ সালে আমেরিকান মাননিয়ন্ত্রক সংস্থা (American National Standards Institute ; সংক্ষেপে ANSI) C এর ১টি আদর্শ ভার্সন তৈরির জন্য কমিটি গঠন করে। দীর্ঘ ৬ বছর পরে ১৯৮৯ সালে সেই আদর্শ সি ভাষাটি তৈরি হয়, যা আমেরিকান মাননিয়ন্ত্রক সংস্থা C (আনসি সি (ANSI C)) নামে পরিচিত। পরবর্তিতে আন্তর্জাতিক মাননিয়ন্ত্রক সংস্থা (ISO) ১৯৯০ সালে C এর এই আদর্শ ভার্সনটি গ্রহণ করে, যা C90 নামে পরিচিত। মুলত "C89" এবং "C90" একই ভাষা। যুগের প্রয়োজনে আন্তর্জাতিক মাননিয়ন্ত্রক সংস্থা ১৯৯৫ সালে এই সংস্করণকে বর্ধিত করে এবং পরবর্তিতে ১৯৯৯ সালে সম্পূর্ণ নতুন একটি সংস্করণ প্রকাশ করে যা C99 নামে পরিচিত। সর্বশেষ ২০১১ সালে সি প্রোগ্রামিং ল্যাঙ্গুয়েজের নবীনতম সংস্করণ C11 প্রকাশিত হয়।




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



প্রোগ্রামিং দক্ষতা


প্রোগ্রামিং দক্ষতা বৃদ্ধি করতে C অতুলনীয় একটি প্রোগ্রামিং ভাষা। তারমানে এই নয় যে C ভাষা শিখলেই তুমি প্রোগ্রামিং এ দক্ষ হয়ে যাবে।


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

বাংলা ভাষা ব্যবহার করতে পারলেই যেমন, তা দিয়ে সাহিত্য রচনা করা যায় না ঠিক তেমনি, কোন প্রোগ্রামিং ল্যাংগুয়েজ এর নিয়মকানুন (syntax) মুখস্ত, কণ্ঠস্থ বা ঠোটস্থ করলেই তুমি খুব ভালো ভালো প্রোগ্রামার হয়ে যাবে ব্যাপারটা তা নয়। প্রোগ্রামার হতে গেলে তোমাদের নিয়মকানুন গুলোকে বিভিন্ন ক্ষেত্রে সৃজনশীল উপায়ে কিভাবে ব্যবহার করা যায়, সেটা নিয়ে ভাবতে হবে।



বেসিক উপাদান


C এর বেসিক উপাদান গুলো প্রায় সকল প্রোগ্রামিং ভাষাকেই  কভার করে। সব প্রোগ্রামিং ল্যাঙ্গুয়েজ এই ভ্যারিয়েবল, if-else, loop, swich case, function, array ইত্যাদি এর ধারণা আছে। আর এই সব কিছুর ধারণা C থেকে নিবো আমরা। আর এই ধারণা আমরা একবার পেয়ে গেলে আমাদের নতুন প্রোগ্রামিং ভাষা শিখতে বেশি কষ্ট হবেনা।



C দিয়ে তৈরি কিছু জনপ্রিয় সফটওয়্যার -

 

  • ওরাকল - এটা ডাটাবেজ সফটওয়্যার
  • এন্ড্রয়েড এর কোর লাইব্রেরি সি দিয়ে লেখা
  • MySQL - এটাও একটা ডাটাবেজ সফটওয়্যার
  • প্রায় সকল ডিভাইস ড্রাইভার সি দিয়ে লেখা
  • প্রতিটা ওয়েব ব্রাউজার এর প্রধান অংশ সি দিয়ে লেখা
  • Unix অপারেটিং সিস্টেম ডেভেলপ হয়েছে সি দিয়ে


সি ভাষায় সফটওয়্যার কিভাবে তৈরি হয় ?


আমাদের সবাই জানি যে .exe ফাইল একটি সফটওয়্যার। মনে করো, এখন আমরা একটা সফটওয়্যার বানাব যার নাম calculator.exe । এখন বিষয়টা হলো .exe ফাইল আমরা বানাবো কিভাবে, .exe  ফাইল অনেক গুলো ০ আর ১ এর সমাবেশ। আর ০,১ মেশিন ভাষা, আর এই ভাষায় কোড করা অনেক কঠিন এবং কোড লিখতেও অনেক কষ্ট হয়। আচ্ছা ধরো আমরা .exe ফাইল বানিয়েও ফেললাম কিন্তু .exe তো অপারেটিং সিস্টেম ডিপেন্ডেন্ট যেটা অন্য কোনো অপারেটিং সিস্টেম এর জন্য উপযোগি না। তাহলে কি করতে হবে অন্য অপারেটিং সিস্টেম এর জন্য আমাদের আবার নতুন করে কোড লিখতে হবে ঐ অপারেটিং সিস্টেম এর ফরমেট অনুযায়ী। তাহলে ভাব তোমাকে কত কষ্ট করতে হবে ?

এর থেকে সহজ উপায় হলো আমরা একটা সহজ ভাষা শিখবো আর সেটা হলো C ল্যাঙ্গুয়েজ। C ল্যাঙ্গুয়েজ এ আমরা কোড করবো আর এই কোড থেকে যেই ফাইল তৈরি হবে সেটাকে বলা হয় সোর্স ফাইল। আর এই ফাইল এর এক্সটেনশন .c হবে। এই ফাইল এর মধ্যে আমরা C ল্যাঙ্গুয়েজ দিয়ে যে সব নির্দেশনা বা ইন্সট্রাকশন লিখেছি, সেটা আমাদের মেশিন দিয়ে করতে হবে। কিন্তু .c ফাইল এটা সফটওয়্যার না কারণ অপারেটিং সিস্টেম .exe ফাইল কে বুজতে পারে .c ফাইল বুজতে পারে না। তারমানে অপারেটিং সিস্টেম C ল্যাঙ্গুয়েজ বুঝে না।

আচ্ছা তাহলে আমরা .c ফাইল কেন বানালাম ?


কারণ C ল্যাঙ্গুয়েজ হার্ডওয়্যার ইন্ডিপেন্ডেন্ট  এবং এতে প্রোগ্রাম তৈরি করা ও সহজ। ধরো আমাদের দুইটা নম্বর অ্যাড এর একটি প্রোগ্রাম বানাতে হবে তাহলে (২ + ৩) লিখলেই হয়ে গেল (এইটা আমরা প্রোগ্রাম করার সময় ভালো মতো বুজবো) কিন্তু আমাদের যদি .exe ফাইল এ কোডিং করতে হয় তাহলে ওখানে ০ এবং ১ এর কিছু কোডিং করতে হতো আর সেটা আমাদের জন্য সুবিধাজনক না।  এখন ধরো আমরা একটা ক্যালকুলেটর এর প্রোগ্রাম লিখে ফেলেছি এবং সোর্স কোডটি  calculator.c নাম এর ফাইল এ আছে।

এখন আমাদের দরকার .c ফাইলকে সফটওয়্যার এ কনভার্ট করা কারণ .c ফাইল সফটওয়্যার না। এই কাজটা করার জন্য সবচেয়ে প্রথমে যেটা দরকার সেটা হলো প্রিপ্রসেসর সফটওয়্যার।

প্রিপ্রসেসর সফটওয়্যার কি করে বা এর কাজ কি ?


একটা প্রোগ্রাম এ যত গুলো স্টেটমেন্ট "#" দিয়ে  শুরু হয় সেই স্টেটমেন্ট গুলো হেন্ডেল করে প্রিপ্রসেসর সফটওয়্যার।  আমরা পরে বিস্তারিত জানব যে, "#" দিয়ে শুরু স্টেটমেন্ট কি কাজ করে।

আমাদের প্রোগ্রাম তৈরির সময় অনেক গুলো হেডার ফাইল অ্যাড করতে হয় যে গুলো আমাদের তৈরি না। কিন্তু এই ফাইল এর ভিতরের কোড গুলো আমাদের কোড এর সাথে অ্যাড করা গুরুত্বপূর্ণ।  আমরা কোড এর মধ্যে এমন কিছু লাইন লিখি যার কারণে প্রিপ্রসেসর হেডার ফাইল এর কনটেন্ট গুলো কে আমাদের ফাইল এর কনটেন্ট এর সাথে মিশিয়ে একটা নতুন ফাইল তৈরি করে। যার এক্সটেনশন .i তার মানে calculator.c এই ফিলকে প্রিপ্রসেসর এ কনভার্ট করলে calculator.i  নাম একটি ফাইল তৈরি হবে। এই নতুন ফাইলটা আমাদের ফাইল এর মতোই শুধু "#" দ্বারা শুরু ওই সকল স্টেটমেন্ট গুলোর পরিবর্তে কিছু অন্য স্টেটমেন্ট অ্যাড হয়েছে যেই স্টেটমেন্ট গুল ঐ হেডার ফাইল এর মধ্যে ছিল।

সাধারণত, প্রিপ্রসেসর "#" দিয়ে শুরু সকল স্টেটমেন্ট হ্যান্ডেল করে। আর সবচেয়ে জনপ্রিয় স্টেটমেন্ট হলো #include, যেমন আমরা প্রতিটা প্রোগ্রাম এ #include<stdio.h> এই স্টেটমেন্টটা আমরা লিখি, এইটা একধরণের কম্যান্ড যার মানে হেডার ফাইল stdio.h এর মধ্যে যেই কনটেন্ট গুল আছে তা প্রোগ্রাম এর সাথে যুক্ত হয়ে যাও।

প্রিপ্রসেসর এর মাধ্যমে calculator.i নামে যেই ফাইলটা তৈরি হয়েছে সেইটা এখন কম্পাইলার সফটওয়্যার এর মাধ্যমে ট্রান্সলেট করতে হবে।  কম্পাইলার ওই প্রোগ্রাম ফাইলকে ট্রান্সলেট করে একটা ফাইল তৈরি করে যেটাকে বলা হয় অবজেক্ট (calculator.obj/calculator.o) ফাইল।

অবজেক্ট ফাইল কোন একটা নির্দিষ্ট অপারেটিং সিস্টেম এর হিসেবে চুড়ান্ত সফটওয়ার তৈরি হয়।  কম্পাইলার, আলাদা আলাদা অপারেটিং সিস্টেম জন্য আলাদা আলাদা ভাবে তৈরি হয়। কিছু কম্পাইলার কোডেকে ডস অপারেটিং সিস্টেম এর হিসেবে ট্রান্সলেট করে আবার কিছু কম্পাইলার লিনাক্স অপারেটিং সিস্টেম এর হিসেবে ট্রান্সলেট করে। কম্পাইলার যেটা তৈরি করেছে সেটাকে অবজেক্ট বলে যেটার এক্সটেনশন .obj /.o।

এর পর আমাদের দরকার হয় লাইব্রেরি ফাইল এর কারণ অবজেক্ট ফাইল এ এমন কিছু লেখা আছে যা অপারেটিং সিস্টেম এর বোঝার ক্ষমতা নাই কিন্তু সেই গুলোর অর্থ লাইব্রেরি ফাইল এর মধ্যে আগে থেকেই থাকে।

বিষয়টা কিছুটা এমন তুমি একটা ইংরেজি বই পড়তে শুরু করেছো সেই বই এর মধ্যে এমন কিছু শব্দ আছে যার অর্থ তুমি জাননা তখন তুমি ডিকশনারীর ব্যবহার করো। ঠিক তেমনি অপেরেটিং সিস্টেম যেই শব্দ গুল বুঝবে না তার জন্য আগে থেকেই লাইব্রেরি ফাইল এর মধ্যে অর্থ গুল দেয়া থাকে।

লাইব্রেরি ফাইল এর কোড এবং অবজেক্ট ফাইল এর কোড লিংক করার জন্য লিংকার সফটওয়্যার ব্যবহার হয়। লিংকার অবজেক্ট ফাইল এন্ড লাইব্রেরি এর কানেক্ট করে একটা নতুন ফাইল তৈরি করে আর সেটাই হলো .exe ফাইল। যেই ফাইল এর অপেক্ষায় আমরা ছিলাম কি তাইতো ? তাহলে সর্বশেষ যে ফাইলটি আমরা পাব তা calculator.exe ফাইল। এই .exe ফাইলটাই আমাদের সফটওয়্যার।






তারমানে আমাদের C ল্যাঙ্গুয়েজ ভাল মতো শিখতে হবে তাহলেই আমরা যা চাইব তাই কম্পিউটারকে দিয়ে করতে পারব। তারপর, ইচ্ছা মতো প্রোগ্রাম লিখে কিছু সফটওয়্যার এর মাধ্যমে আমরা আমাদের প্রোগ্রামকে সফটওয়্যার এ পরিবর্তন করে ফেলব।

এখন বলো তুমি যদি তোমার তৈরি করা একটা সফটওয়্যার তোমার বন্ধুকে দিতে চাও তাহলে তুমি কোন ফাইল দিবা ?



স্কোপ : C ভাষায় Scope এর ধারণা

যারা প্রোগ্রামিং ভাল করে বুঝতে চান স্কোপ সম্পর্কে ধারণা থাকা তাদের জন্য আবশ্যিক।

স্কোপ হচ্ছে একটি এলাকা। স্কোপ হচ্ছে এমন একটি এলাকা যে এলাকায় কোন ভ্যারিয়েবল এর নিজস্ব অস্তিত্ব বিদ্যমান।

সব ভ্যারিয়েবল এরই নির্দিষ্ট স্কোপ আছে। স্কোপ হচ্ছে ভ্যারিয়েবল এর নিজস্ব এলাকা। নিজস্ব স্কোপের বাইরে কোন ভ্যারিয়েবল অর্থহীন, অস্তিত্বহীন।

কোন ভ্যারিয়েবলকে যে স্কোপে ডিক্লেয়ার করা হয়, সেই স্কোপ ও তার অভ্যন্তরীণ অন্যান্য স্কোপে সেটি কাজ করতে পারে। তার বাইরের অন্য কোন এলাকায় বা স্কোপে সে কাজ করতে পারে না।

আমরা যখন একটি ফাকা ফাইলে কোড লিখা শুরু করি, তখন সমগ্র ফাকা জায়গাটিই একটি স্কোপ হিসেবে কাজ করে যাকে গ্লোবাল স্কোপ বলে। এই গ্লোবাল স্কোপে যেসব ভ্যারিয়েবল ডিক্লেয়ার করা হয় তারা এই সমগ্র গ্লোবাল স্কোপ ও এর অভ্যন্তরীণ অন্যান্য স্কোপে কাজ করতে পারে। অভ্যন্তরীণ স্কোপ গুলোকে বলা হয় লোকাল স্কোপ।

মূলত এই কারণেই সমস্ত ফাংশনগুলোকে গ্লোবাল স্কোপে ডিক্লেয়ার করা হয় যাতে ঐ প্রোগ্রামের যে কোন অংশে তারা ব্যবহৃত হতে পারে।

গ্লোবাল স্কোপকে অনেকগুলো লোকাল স্কোপে ভাগ করা যায়। একজোড়া কার্লি ব্রেস দিয়ে স্কোপের সীমানা নির্ধারণ করা হয়। উদাহরণস্বরূপ আমরা বলতে পারি main() ফাংশন এর পরের কার্লি ব্রেসের কথা। ওপেনিং ব্রেস থেকে ক্লোজিং ব্রেস পর্যন্ত পুরা এলাকাটিই main() ফাংশনের লোকাল স্কোপ।

কোন স্কোপে যখন কোন ভ্যারিয়েবল ডিক্লেয়ার করা হয় তখন তা ঐ স্কোপে অস্তিত্বশীল। ঐ স্কোপে ঐ নামে আর কোন ভ্যারিয়েবল ডিক্লেয়ার করা যায় না। কিন্তু ভিন্ন ভিন্ন স্কোপে একই নামের একাধিক ভ্যারিয়েবল থাকতে পারে। কারণ, তাদের নাম এক হলেও, স্কোপ ভিন্ন হবার কারণে তারা আসলে ভিন্ন ভিন্ন সত্ত্বা। যেমনঃ

#include<stdio.h>

int main()
{
    int x;
    char x;

return 0;
}

উপরের কোড সেগমেন্ট রান করলে এরর দেখাবে। কিন্তু,

#include<stdio.h>
int x;
int main()
{
    char x;

return 0;
}

কোডটি কোন এরর দেখাবে না। কারণ, x কে দুইটি ভিন্ন ভিন্ন স্কোপে দুইবার ডিক্লেয়ার করা হয়েছে, যা লিগ্যাল।

যদি দুইটি ভিন্ন ভিন্ন স্কোপে একই নামের ভ্যারিয়েবল থাকে তাহলে যে ভ্যারিয়েবল যে স্কোপে আছে সেই স্কোপে সেই নামে ব্যবহার করলে সেই ভ্যারিয়েবলই ব্যবহৃত হবে। অন্য স্কোপের ভ্যারিয়েবল এখানে ব্যবহৃত হবে না। একই নামে গ্লোবাল ও লোকাল স্কোপে দুইটি ভ্যারিয়েবল x থাকলে লোকাল স্কোপে x কে ব্যবহার করলে লোকাল স্কোপের x ই ব্যবহৃত হবে, গ্লোবাল x নয়।

আবারো বলি যে কার্লি বেস দিয়ে আলাদা করা প্রত্যেকটি এলাকার স্কোপই আলাদা। স্কোপ সমূহের দ্বায়ের ধারা অন্তর্মুখী। অর্থাৎ,  কোন স্কোপে ডিক্লেয়ার হওয়া ভ্যারিয়েবল কেবল সেই স্কোপ ও তার অভ্যন্তরীণ স্কোপ সমূহে ব্যবহৃত হতে পারবে। বাইরের কোন ফাংশন বা অপারেশন ই সরাসরি অভ্যন্তরীণ কোন স্কোপের কোন উপাদান এক্সেস, ব্যবহার বা পরিবর্তন করতে পারবে না।

গ্লোবাল স্কোপে ডিক্লেয়ার হওয়া ভ্যারিয়েবলকে গ্লোবাল ভ্যারিয়েবল বলে। যেমনঃ ফাংশন সমূহ সব সময়ই গ্লোবাল।

গ্লোবাল স্কোপে থাকা উপাদানসমূহ সবাই ব্যবহার করতে পারে, সবাই তাদের পরিবর্তন করতে পারে।

কোন ভ্যারিয়েবল ডিক্লেয়ার করার সময় তা মেমরিতে কিছু স্থান দখল করে। যতক্ষন তার স্কোপের কাজ শেষ না হয় ততক্ষন সে স্থান দখল করেই থাকে। স্কোপের কাজ শেষ হলেই সেটি বিলুপ্ত হয়ে যায়। একে "স্কোপের বাইরে চলে যাওয়া" (out of scope) বলে।

কাজেই গ্লোবাল কোন ভ্যারিয়েবল প্রোগ্রাম চলাকালীন পুরো সময়ই মেমরিতে তার স্থান দখল করে রাখে, আর লোকাল ভ্যারিয়েবলগুলো যতক্ষন স্কোপের মধ্যে থাকে ততক্ষন স্থান দখল করে থাকে আর স্কোপের বাইরে চলে গেলেই সেই মেমরি ফাকা হয়ে যায়।

কাজেই একজন দক্ষ প্রোগ্রামার সব সময়ই খেয়াল রাখে যে সে কোন স্কোপে কোন কাজ সম্পাদন করছে।

এবার একটি প্রশ্ন করি। নিচের কোড খেয়াল করেন,

#include<stdio.h>

int x=100;

int main()
{
    int x=50, y=10;

    if (x>10)
    {
        int y=50;
        printf("%d\n", x+y);
        x=10;
     }
     printf("%d", x+y);

return 0;
}

এই প্রোগ্রামের আউটপুট কি হবে? আমি জানি অনেকেই চিন্তা করা বাদ দিয়ে এটি রান করিয়ে দেখবেন। আচ্ছা বলেন দেখি, আউটপুট অমন কেন হলো???

এক্সেকিউশান ও রান : Execution ও Run

প্রোগ্রামিং ল্যাংগুয়েজ এর জগতে execution কথাটির অর্থ হচ্ছে কোন কোড সেগমেন্ট বা কোন স্টেটমেন্ট এ যে ইন্সট্রাকশন বা নির্দেশনা থাকে তা মেশিন কর্তৃক সম্পাদিত হওয়া।

তবে আমরা আমাদের লেখায় এক্সেকিউশানকে একটু ভিন্ন অর্থে ব্যবহার করবো।

সম্পূর্ণ প্রোগ্রাম এক্সেকিউট করাকে আমরা বলবো রান (Run) করা। আর প্রোগ্রামের কোন কোড সেগমেন্ট বা অংশ বিশেষকে এক্সেকিউট করাকে আমরা বলবো এক্সেকিউশান বা এক্সেকিউট করা।

কাজেই আমাদের আলোচনায় আমরা একটি পূর্ণ প্রোগ্রামকে রান করবো, আর কোড সেগমেন্ট কে এক্সেকিউট করবো।

আশা করি, বিভিন্ন পোস্টে যখন এক্সেকিউট আর রান শব্দ দুইটি ব্যবহার করা হবে, তখন আর বুঝতে সমস্যা হবে না।

C স্টেটমেন্ট : statement কি?

C ভাষায় কোন প্রোগ্রামে উপস্থিত একটি পূর্ণ নির্দেশনাকে বলা হয় স্টেটমেন্ট। স্টেটমেন্ট হচ্ছে অনেকটা C ভাষার বাক্যের মত।

অর্থাৎ, একটি স্টেটমেন্ট দ্বারা কোন প্রোগ্রামের ক্ষুদ্রতম কিন্তু পূর্ণাঙ্গ একটি কাজ সম্পাদন হবে। গঠনগত ভাবে স্টেটমেন্ট ২ ধরনের।

১. simple স্টেটমেন্ট
২. compound স্টেটমেন্ট

simple স্টেটমেন্ট হচ্ছে একটি মাত্র সরল বাক্যের মত। একটি সেমিকোলন দ্বারা কোন simple স্টেটমেন্ট এর সমাপ্তি নির্দেশ করা হয়। যেমনঃ

int x; একটি ডিক্লেয়ারেশন স্টেটমেন্ট,
x=5; একটি এসাইনমেন্ট স্টেটমেন্ট,
scanf("%d", &x); একটি কলিং স্টেটমেন্ট,
আবার,
if (x>0)
    printf("%d", x); একটি কন্ডিশনাল স্টেটমেন্ট।

একটি simple স্টেটমেন্ট এ সাধারণত একটি মাত্র কাজ করার নির্দেশনা থাকে।

Compound স্টেটমেন্ট হচ্ছে অনেকগুলি simple স্টেটমেন্ট এর একটি সমন্বয় যা কার্যগত ভাবে একটি বড় আকারের স্টেটমেন্ট এর মত কাজ করে। compound স্টেটমেন্ট লিখার সময় কার্লি ব্রেস '{}' ব্যবহার করা হয়। এটি হচ্ছে জটিল বাক্যের মত। compound স্টেটমেন্ট এর অন্তর্গত প্রত্যেকটি simple স্টেটমেন্ট ই নিয়ম অনুযায়ী সেমিকোলন দিয়ে শেষ করা হয়। তবে compound স্টেটমেন্ট এর সমাপ্তি নির্দেশক হচ্ছে কার্লি ব্রেস এর ক্লোজিং ব্রেস '}'। যেমন,

if (x>0)
{
    y=x+1;
    printf("%d", y);
}

এই কন্ডিশনাল স্টেটমেন্টটি একটি compound স্টেটমেন্ট। একটি নির্দিষ্ট শর্তের অধীনে যদি আমরা একাধিক কাজ করতে চাই তাহলে অবশ্যই compound স্টেটমেন্ট তৈরী করতে হবে, অর্থাৎ কার্লি ব্রেস ব্যবহার করতে হবে। উপরের উদাহরনে if স্টেটমেন্ট এর কন্ডিশন True হলে কার্লি ব্রেস এর ভেতরকার প্রত্যকেটি লাইনই এক্সেকিউট হবে।

কার্যগত ভাবে কোন স্টেটমেন্ট কে তার কাজ এর উপর ভিত্তি করে বা যে কিওয়র্ড ব্যবহার করে স্টেটমেন্ট টি কাজ করে তার নামে ডাকা হয়। যেমন,


  • ডিক্লেয়ারেশন স্টেটমেন্টঃ ভ্যারিয়েবল, ফাংশন ইত্যাদি ডিক্লেয়ার করার জন্য।
  • এসাইনমেন্ট স্টেটমেন্টঃ এসাইনমেন্ট অপারেটর '=' ব্যবহার করা হয় যে স্টেটমেন্ট এ।
  • কন্ট্রোল স্টেটমেন্টঃ কন্ডিশনাল স্টেটমেন্ট if, else, switch, লুপ স্টেটমেন্ট for, while, do, জাম্প স্টেটমেন্ট goto, return ইত্যাদি, যারা কোড এক্সেকিউশান এর ধারাবাহিতা নিয়ন্ত্রণ করে।
  • কলিং স্টেটমেন্টঃ ফাংশন কল নিয়ে যে সব স্টেটমেন্ট তৈরী হয়।


এরকম বিভিন্ন ধরনের স্টেটমেন্ট থাকতে পারে। কোন স্টেটমেন্ট এক্সেকিউট করা মানে হচ্ছে সেই স্টেটমেন্ট এর শুরু থেকে সমাপ্তি পর্যন্ত যত কাজের নির্দেশনা, বা ইন্সট্রাকশন ছিলো তার সবটুকু সম্পন্ন করা।

C এর উপাদান সমূহঃ ফাংশন

.১ - ফাংশন কি?

ফাংশন হচ্ছে যে কোন প্রসিডিউরাল প্রোগ্রামিং ল্যাংগুয়েজ এর বিল্ডিং ব্লক বা গঠনগত একক। C যেহেতু একটি প্রসিডিউরাল ল্যাংগুয়েজ সেহেতু C ও তার ব্যতিক্রম নয়।



একটি C প্রোগ্রাম মানে হচ্ছে অনেকগুলো ফাংশন কলের একটি সিরিজ। প্রত্যেকটি ফাংশনই তার কোড অনুযায়ী নির্ধারিত কাজ সম্পাদন করে থাকে।

.২ ফাংশনের প্রকারভেদ

C ভাষায় প্রোগ্রামে দুই ধরনের ফাংশন ব্যবহার করা হয়।

১. প্রিডিফাইন্ড লাইব্রেরী ফাংশন বা বিল্ট ইন ফাংশনঃ এই সব ফাংশন C স্ট্যান্ডার্ড লাইব্রেরী তে আগে থেকেই তৈরী করা আছে। আমরা শুধু এই সব ফাংশন ব্যবহার করতে পারি, কিন্তু এদের কার্য নিয়ন্ত্রক কোড সমূহ পরিবর্তন করতে পারি না। যেমন, ইনপুট ফাংশন scanf() এবং আউটপুট ফাংশন printf() লাইব্রেরী ফাংশনের উউদাহরণ ফাংশন। লাইব্রেরী ফাংশন ব্যবহারের জন্য যথাপোযুক্ত হেডার ফাইল প্রোগ্রামের শুরুতেই যুক্ত করে নিতে হয়। মূলত এই কারণেই প্রত্যেকটি প্রোগ্রামের শুরুতে #include<stdio.h> লিখা হয়। STDIO.H হেডার ফাইলে সকল স্ট্যান্ডার্ড ইনপুট ও আউটপুট ফাংশন আগে থেকেই ডিফাইন করা আছে।

২. ইউজার ডিফাইন্ড ফাংশন বা সাব রুটিনঃ বেশির ভাগ সময়ই লাইব্রেরী ফাংশনের বাইরেও আমাদের অনেক কাজ করতে হয় এবং সেই সব কাজ সুন্দর ভাবে করার জন্য ফাংশন তৈরী করার দরকার পড়ে। ইউজার ডিফাইন্ড ফাংশন হচ্ছে এমন এক ধরনের ফাংশন যা প্রোগ্রামার নিজের সুবিধার জন্য নিজেই তৈরী করে থাকেন। ইউজার ডিফাইন্ড ফাংশনকে সাব রুটিনও বলা হয়ে থাকে। কাজেই আমরা যদি কোথাও রুটিন ও সাব রুটিন লেখা দেখি তাহলে বুঝে নিতে হবে যে তারা আসলে ফাংশনকেই বুঝাচ্ছে।

একটি C প্রোগ্রামে কমপক্ষে ১ টি ফাংশন থাকতে হয়। main() হচ্ছে সেই ফাংশন যার উপস্থিতি সব C প্রোগ্রামে আবশ্যিক। যে কোন C প্রোগ্রামের এক্সেকিউশান শুরু হয় main() ফাংশন থেকে। ১ টি প্রোগ্রামে কেবলমাত্র ১ টি main() ফাংশন থাকতে পারে।

main() হচ্ছে ১ টি বিশেষ ধরনের ইউজার ডিফাইন্ড ফাংশন। এটি বিশেষ হবার কারণ হচ্ছে, এটি ইউজার ডিফাইন্ড হওয়া সত্ত্বেও এটি C লাইব্রেরীতে ডিফাইন করা থাকে। C স্পেসিফিকেশন অনুযায়ী main() ফাংশনের কিছু কিছু আচরণ ও গঠন খানিকটা নির্দিষ্ট। আবার ইউজার ডিফাইন্ড ফাংশন হওয়ার কারণে প্রোগ্রামার নিজের ইচ্ছা মত কাজ তাকে দিয়ে করাতে পারে, তার মধ্যে নিজের ইচ্ছামত কোড লিখতে পারে।

.৩ - ফাংশনের সাধারন গঠন

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

১. রিটার্ন টাইপ
২. ফাংশনের নাম
৩. প্যারামিটার লিস্ট
৪. ফাংশনের মূল অংশ বা বডি

ret_type func_name (parameter_list)
{
    /* ফাংশন বডি */

}

আসুন দেখা যাক এগুলো আসলে কি।

১. রিটার্ন টাইপঃ যখন কোন ফাংশনকে কল করা হয়, অর্থাৎ কাজ করার জন্য ডাকা হয় তখন যে ফাংশনের মধ্যে তাকে ডাকা হয়, সেই ফাংশনকে বলে কলিং ফাংশন। ডাকা ফাংশনটি তার কাজ শেষ  করার পরে অনেক সময়ই কলিং ফাংশনকে কিছু ডেটা ফেরত দেয়। রিটার্ন টাইপ নির্ধারণ করে দেয় যে কোন ফাংশন তার কলিং ফাংশনকে কোন ধরনের ডেটা ফেরত বা রিটার্ন দিবে। রিটার্ন টাইপ যে কোন ডেটা টাইপের হতে পারে। যদি কোন ফাংশন কোন ডেটা রিটার্ন না দেয় বা রিটার্ন দেওয়া ডেটা যদি নির্দিষ্ট কোন টাইপের না হয় তখন সে ফাংশনের রিটার্ন টাইপ হয় void।

যে ডেটা রিটার্ন দেওয়া হয় তাকে রিটার্ন ভ্যালু বলে। কোন ফাংশনের রিটার্ন ভ্যালু হচ্ছে সেই ফাংশনের চুড়ান্ত মান। যদি কোন ফাংশন কোন সমীকরণ এর অংশ হয় তাহলে সেই সমীকরণ এ ঐ ফাংশনের মান হিসেবে তার রিটার্ন ভ্যালু ব্যবহৃত হয়। যারা ম্যাথমেটিকস এ ফাংশন পড়েছেন তারা ব্যাপারটা ভালো বুঝবেন। তবে একটু পরেই এই ব্যাপারে আরো উদাহরণ দেওয়া হবে।

২. ফাংশনের নামঃ ফাংশনের নাম হচ্ছে ফাংশনের পরিচয়। যখন কোন ফাংশনকে কল করা হয়, তখন তার নাম ব্যবহার করেই তাকে কল করা হয়। একই C প্রোগ্রামে একই নামের কেবল ১ টি ফাংশন থাকতে পারে।

৩. প্যারামিটার লিস্টঃ অনেক সময় কলিং ফাংশন কিছু ডেটা কল করা ফাংশনটিকে সরবরাহ করে থাকে কল করার সময়েই। এই সব ডেটা ব্যবহার করেই কল করা ফাংশনটি তার কাজ সম্পাদন করে। কলিং ফাংশন যে সব ডেটা সরবরাহ করে তাদেরকে আর্গুমেন্ট বলে। আমরা জানি যে, যে কোন ডেটা রাখার জন্য ভ্যারিয়েবল দরকার হয়। কল করা ফাংশনটি কলিং ফাংশন থেকে আলাদা। তাই কলিং ফাংশন যে আর্গুমেন্ট সরবরাহ করবে তা জমা রাখার জন্য কল করা ফাংশনটির প্রয়োজনীয় ভ্যারিয়েবল থাকতে হবে। এই ভ্যারিয়েবল এর নাম হচ্ছে প্যারামিটার। আর্গুমেন্ট গ্রহণ করার জন্য ফাংশনের যে সব ভ্যারিয়েবল ডিক্লেয়ার করা দরকার হয়, তাদেরকে ফাংশনের নামের পরে ফার্স্ট ব্র‍্যাকেট এর মধ্যে কমা দিয়ে আলাদা করে উল্লেখ করা হয়, এবং এই কমা দিয়ে আলাদা করা ভ্যারিয়েবল লিস্ট কেই প্যারামিটার লিস্ট বলা হয়।

কলিং ফাংশন কল করা ফাংশনকে কল করার সময় যে ডেটা সরবরাহ করে তাকে বলা হয় আর্গুমেন্ট। আর আর্গুমেন্ট গ্রহন করা ও জমা রাখার জন্য কল করা ফাংশনে যে সব ভ্যারিয়েবল থাকে তাদের বলা হয় প্যারামিটার।

যে ফাংশনের কোন প্যারামিটার থাকে না তার নামের পরে ফার্স্ট ব্র‍্যাকেটের মধ্যে void কথাটি লিখা হয়। অন্যান্য ক্ষেত্রে ফাংশনের এক বা একাধিক প্যারামিটার থাকতে পারে। সর্বোচ্চ কয়টি প্যারামিটার কোন ফাংশনের থাকতে পারবে সেটা কম্পাইলার এর উপর নির্ভর করে। তবে ANSI C স্ট্যান্ডার্ড অনুযায়ী, কমপক্ষে ৩১ টি প্যারামিটার দেওয়ার ক্ষমতা সব কম্পাইলার কেই রাখতে হবে।

৪. ফাংশন বডিঃ ফাংশন বডি হচ্ছে ফাংশনের মূল অংশ যেখানে ফাংশনটি যে কাজ সম্পাদনের জন্য তৈরী সেই কাজ সম্পাদনের কোড লিখা থাকে। প্যারামিটার লিস্টের পরে একজোড়া কার্লি ব্রেস ( '{}' কে আমরা কার্লি ব্রেস বলবো) এর মধ্যে ফাংশনের বডি অবস্থিত। '{' ওপেনিং ব্রেস আর '}' কে ক্লোজিং ব্রেস বলা হয়। ওপেনিং ব্রেসের পর থেকে কোড এক্সেকিউশান শুরু হয়, এবং অন্য কোন রিটার্ন পয়েন্ট না থাকলে ক্লোজিং ব্রেস পর্যন্ত গিয়ে ফাংশন তার কলিং ফাংশনে রিটার্ন করে।

কোন ফাংশনকে কল করার সময় তার নাম এবং ফার্স্ট ব্র‍্যাকেটের মধ্যে প্যারামিটার লিস্ট অনুযায়ী আর্গুমেন্ট সহ ফাংশন কল করতে হয়। যেমন,

void func(void)
{
    /*function body*/
}

ফাংশনটি কল করার জন্য func(); লিখাই যথেষ্ঠ। কিন্তু,

ret_type func1(parameter_1, parameter_2)
{
    /*function body*/
}

ফাংশনটি কল করার জন্য লিখতে হবে

func1(argument_1, argument_2);

আমাদের পরিচিত লাইব্রেরী ফাংশন printf() এর কথা যদি বিবেচনা করি তাহলে দেখতে পাবো যে, printf() ফাংশনের গঠন হচ্ছে,

int printf ("আউটপুট স্ট্রিং", প্যারামিটার লিস্ট);

printf() এর ক্ষেত্রে "আউটপুট স্ট্রিং" অংশটা বাধ্যতামূলক আর প্যারামিটার লিস্ট অপশনাল। তাই printf() কে কল করার জন্য এর মধ্যে প্রথম আর্গুমেন্ট হিসেবে কোটেশন মার্ক সহ একটি স্ট্রিং দিতেই হবে, আর আমাদের যদি দরকার পড়ে তাহলে অন্যান্য আর্গুমেন্ট সরবরাহ করতে পারবো।

.৪ - ইউজার ডিফাইন্ড ফাংশন


উপরে আমরা main() নামক বিশেষ ইউজার ডিফাইন্ড ফাংশনের কথা বলেছি। এইবার আমরা অন্যান্য ইউজার ডিফাইন্ড ফাংশন নিয়ে কিছু কথা বলবো।
একাধিক ইউজার ডিফাইন্ড ফাংশন আছে এমন একটি C প্রোগ্রামের গঠন নিম্নরূপঃ

/* হেডার বা লিংকার সেকশন */

/* প্রোটোটাইপ ডিক্লেয়ারেশন। ইউজার ডিফাইন্ড ফাংশন এর জন্য এটি আবশ্যিক */

int main()
{
    /* ফাংশন বডি */
}

ret_type fn1(parameter_list)
{
    /*fn1 এর বডি*/
}

ret_type fn2(parameter_list)
{
    /*fn2 এর বডি*/
}

fn1 আর fn2 হল ফাংশনের নাম। প্রোগ্রামার তার পছন্দমত নাম ইউজার ডিফাইনড ফাংশনকে দিতে পারে। তবে নাম সাধারণত তার কাজের সাথে মিল রেখে দেওয়া হয়।

ret_type হচ্ছে ফাংশনগুলোর রিটার্ণ টাইপ। parameter_list এ প্রয়োজন মত প্যারামিটার ডিক্লেয়ার করা হয় এবং কমা দিয়ে একাধিক ডিক্লেয়ারেশন আলাদা করা থাকে।

কোডের ২ নম্বর লাইনে প্রোটোটাইপ ডিক্লেয়ারেশন এর কমেন্টটা খেয়াল করুন। এই প্রোটোটাইপ জিনিসটা কি?

ফাংশন প্রোটোটাইপ হচ্ছে ফাংশনকে ডিফাইন এবং ব্যবহার করার পূর্বে সংক্ষিপ্ত আকারে ডিক্লেয়ার করার নাম যেখানে ফাংশনের বডি অনুপস্থিত থাকে।  অর্থাৎ,  প্রোটোটাইপ এ ফাংশনের রিটার্ন টাইপ, নাম ও প্যারামিটার লিস্ট থাকে, কিন্তু কোন বডি থাকে না। আর প্যারামিটার লিস্ট এর ব্র‍্যাকেট শেষ হবার পরে সেমিকোলন দিয়ে প্রোটোটাইপ ডিক্লেয়ারেশন শেষ করতে হয়। যেমন, fn1 ফাংশনের প্রোটোটাইপ হবে,

ret_type fn1 (parameter_list);

আবার fn2 ফাংশনের প্রোটোটাইপ হবে,

ret_type fn2 (parameter_list);

অর্থাৎ, প্রোটোটাইপ হচ্ছে ফাংশনের বডি লিখা বা তাকে ব্যবহার করার আগে কম্পাইলার কে জানিয়ে রাখা যে, অমুক নামে একটি ইউজার ডিফাইন্ড ফাংশন তৈরি করা হবে যাকে কল করার জন্য অমুক অমুক আর্গুমেন্ট দিতে হবে এবং যা অমুক টাইপের ভ্যালু রিটার্ন দিবে।

সকল ইউজার ডিফাইন্ড ফাংশন এর জন্য প্রোটোটাইপ ডিক্লেয়ারেশন আবশ্যিক। তবে main()  এর জন্য কোন প্রোটোটাইপ ডিক্লেয়ার করতে হয় না। এটি আগে থেকেই C স্ট্যান্ডার্ড লাইব্রেরীতে করা আছে।

প্রোটোটাইপ খুবই গুরুত্বপূর্ণ। এর পূর্ণাঙ্গ গুরুত্ব বুঝতে হলে C ল্যাংগুয়েজ আরেকটু ভাল করে বুঝতে হবে। তবে আপাতত এইটুকু মাথায় রাখলেই যথেষ্ট যে, ইউজার ডিফাইন্ড ফাংশনকে ডিফাইন করার আগে তার প্রোটোটাইপ ডিক্লেয়ার করতে হবে।

অন্য সব ফাংশনের মত ইউজার ডিফাইন্ড ফাংশনকেও তার নাম ও প্যারামিটার লিস্ট অনুযায়ী আর্গুমেন্ট লিস্ট সহ (যদি আদৌ প্যারামিটার থাকে) কল করা হয়। C একটি স্ট্রাকচারড ল্যাংগুয়েজ। তাই একটি C প্রোগ্রামে এক লাইন এক লাইন করে কোড ধারাবাহিক ভাবে এক্সেকিউট হতে থাকে। যখন কোন ইউজার ডিফাইন্ড ফাংশনকে কল করা হয় তখন প্রোগ্রাম এক্সেকিউশান কলিং ফাংশন থেকে সরে গিয়ে কল করা ফাংশনে চলে যায়। কল করা ফাংশনটির ওপেনিং ব্রেস ('{') এরপর যে কোড থাকে তা ধারাবাহিক ভাবে এক্সেকিউট হতে থাকে যতক্ষন পর্যন্ত না কোন return স্টেটমেন্ট না আসে অথবা ক্লোজিং ব্রেস ('}') আসে। এই দুটির যে কোন একটি হলেই ফাংশনটি রিটার্ন করে এবং প্রোগ্রাম এক্সেকিউশান এর ধারাবাহিকতা আবার কলিং ফাংশনে ফেরত আসে। ফাংশন কলের ঠিক পরের কোডটিই এর পরে এক্সেকিউট হয়ে থাকে।

অর্থাৎ, ফাংশন কল করলে প্রোগ্রাম এক্সেকিউশান সাময়িক ভাবে কল করা ফাংশনে চলে যায় এবং তা রিটার্ন করার পরে পূর্বের অবস্থানের ঠিক পরের কোড থেকেই আবার এক্সেকিউশান শুরু হয়।

একটি ইউজার ডিফাইন্ড ফাংশন তার মধ্যে এক বা একাধিক ফাংশনকে কল করতে পারে। প্রথাগতভাবে, main() ফাংশনকে অন্য কোন ফাংশন কল করে না। তবে এতে কোন আইনগত বাধা নেই।

এখন একটি উদাহরন দিই। এই উদাহরণ এ আমরা ২ টি ইউজার ডিফাইন্ড ফাংশন ব্যবহার করবঃ main() এবং func()। আমাদের সুবিধার্থে আমরা ধরে নিবো যে func() এর কোন রিটার্ন টাইপ নেই এবং তার কোন প্যারামিটার ও নেই। নিচের কোডটি দেখুন ও এর আউটপুট কি হতে পারে তা আন্দাজ করুন।

/* প্রোগ্রামের শুরু এখানে */

#include<stdio.h>

void func(void); /* func() এর প্রোটোটাইপ */

int main()
{
    printf("I ");
    func();
    printf(" C.");

return 0;
}

/* func() কে ডিফাইন করা হবে */
void func (void)
{
    printf("like");
}

/*প্রোগ্রামের শেষ এখানে */

আসুন দেখি এই কোডটি কিভাবে এক্সেকিউট হবে। প্রোগ্রাম এক্সেকিউশান শুরু হবে main() থেকে। main()  এর ভেতরে প্রথম লাইনে printf() ফাংশনের কল এক্সেকিউট হবে এবং স্ক্রিনে প্রিন্ট হবে I । তারপরের লাইনে func() কে কল করা হয়েছে। যার ফলে প্রোগ্রাম এক্সেকিউশান func() এর ভেতরে চলে যাবে। func() এর ওপেনিং ব্রেস এর পরে একটি printf() ফাংশন কল আছে। তাই স্ক্রিনে প্রিন্ট হবে like। এর পরেই func()  এর ক্লোজিং ব্রেস থাকায় ফাংশনটি আবার main() এ রিটার্ন করবে এবং func() কে কল করার ঠিক পরের কোড এক্সেকিউট করা শুরু করবে। এখানে এর পরে আছে আরেকটি printf() কল যা স্ক্রিনে প্রিন্ট করবে  C.। এরপর মেইন ফাংশনও রিটার্ন করবে এবং প্রোগ্রাম শেষ হবে। কাজেই এই প্রোগ্রামের আউটপুট হবে,

I like C.

main() এর ভেতরে ২য় লাইনে func() কে কল করা হয়েছে। লক্ষ্য করুন একে শুধু নাম এবং ফাকা ফার্স্ট ব্র‍্যাকেট সহ কল করা হয়েছে। এর কারন এর প্যারামিটার লিস্ট void,  তাই কোন আর্গুমেন্ট ছাড়াই একে কল করা যায়।

যে কোন ফাংশন কলের ক্ষেত্রে ফাংশনটি যে অবস্থান হতে কল করা হয়েছিলো, ফাংশনটি রিটার্ন করার পরে ঠিক তার পরের অবস্থান থেকে প্রোগ্রাম এক্সেকিউশান শুরু হবে।

এক্সারসাইজঃ
১। নিচের কোডের আউটপুট কি হবে? ব্যাখ্যা করুন।

#include<stdio.h>

void func1 (void);
void func2 (void);

int main()
{
    func2();
    printf(" 3");

return 0;
}

void func2 (void)
{
    func1();
    printf("2");
}

void func1 (void)
{
    printf("1 ");
}

২। একটি প্রোগ্রাম লিখুন যেখানে ৩ টি ইউজার ডিফাউন্ড ফাংশন থাকবেঃ main(), txt1() এবং txt2()। txt1() এবং txt2() এর কোন রিটার্ন ভ্যালু বা প্যারামিটার থাকবে না। txt1() এর আউটপুট হবে I am learning C এবং txt2() এর আউটপুট হবে for a better future.। আর সম্পূর্ণ প্রোগ্রামের আউটপুট হবে
I am learning C from this blog for a better future.

.৫ - রিটার্ন টাইপ সহ ফাংশন ব্যবহার

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

কোন ফাংশন যদি তার কলিং ফাংশনকে কোন ডেটা রিটার্ন করে তাহলে সেই ডেটা কে ঐ ফাংশনের রিটার্ন ভ্যালু বলে। আর ঐ ডেটার টাইপ কে বলা হয় ঐ ফাংশনের রিটার্ন টাইপ।

return কিওয়র্ড ব্যবহার করে কোন ভ্যালু রিটার্ন দেওয়া হয়। এই ব্যাপারে বিস্তারিত পড়ুন এখানে।

এই অনুচ্ছেদে আমরা কিছু ফাংশন দেখবো যারা তাদের কলিং ফাংশনে ভ্যালু রিটার্ন দেয়।

ফাংশন যে কোন টাইপের ডেটা রিটার্ন দিতে পারে। তবে সবচে বেশি যে টাইপের ডেটা রিটার্ন দেয় তা হল int। তাই আপাতত আমরা এমন কিছু ফাংশন দেখবো যারা int টাইপের ডেটা রিটার্ন দেয়।

প্রথমেই আমরা একটি লাইব্রেরী ফাংশন দেখি। স্ট্যান্ডার্ড ইনপুট আউটপুট লাইব্রেরীর ফাংশন getchar() কি বোর্ড থেকে ক্যারেকটার টাইপের ডেটা ইনপুট নিয়ে থাকে। প্রত্যেক বার এই ফাংশনকে কল করা হলে সে একটি করে ক্যারেকটার ইনপুট নেয়। মূলত এই ফাংশনটি একটি ক্যারেকটার ইনপুট নিয়ে তাকে কলিং ফাংশনে ফেরত দেয়। এখন কথা হচ্ছে ফাংশন তার কলিং ফাংশনকে ডেটা ফেরত না হয় দিলো। কিন্তু কলিং ফাংশন সেই ডেটা আবার গ্রহন করে কিভাবে? ব্যবহারই বা করে কিভাবে? আসুন দেখি কিভাবে এটা করা হয়ে থাকে।

getchar() ফাংশনের প্রোটোটাইপ হচ্ছে,

int getchar (void);

প্রোটোটাইপ থেকেই বুঝতে পারছি যে এই ফাংশনের রিটার্ন টাইপ int আর এটি কল করতে কোন ধরনের আর্গুমেন্ট লাগে না, কারণ এর প্যারামিটার হচ্ছে void। char টাইপটা হচ্ছে ক্যারেকটার এর ডেটা টাইপ। char টাইপটার অভ্যন্তরীণ গঠন ইন্টিজারের মতই, এবং আকারে int অপেক্ষা ছোট। তাই একটি int ডেটার মধ্যে একটি char ডেটা রিটার্ন দেওয়া যায়। এজন্যেই যদিও getchar() এর মূল লক্ষ্য একটি ক্যারেকটার রিটার্ন দেওয়া, সে ক্যারেকটার টিকে একটি ইন্টিজার হিসেবে রিটার্ন দেয়।

কলিং ফাংশন দুইভাবে getchar() এর কাছ থেকে রিটার্ন ভ্যালু গ্রহণ করতে পারে। আমরা যদি কলিং ফাংশনে একটি ক্যারেকটার টাইপের ভ্যারিয়েবল নিই এবং এসাইনমেন্ট অপারেটর (=) এর মধ্যমে getchar() এর রিটার্ন ভ্যালুকে ঐ ভ্যারিয়েবল এ এসাইন করি তাহলে, ঐ ভ্যারিয়েবলে getchar() এর রিটার্ন ভ্যালু জমা হয়ে যাবে। এইবার আমরা ঐ ভ্যারিয়েবল অন্য কোথাও ব্যবহার করলে সেখানে getchar() রিটার্ন ভ্যালু ব্যবহৃত হবে। যেমন নিচের প্রোগ্রামটি লক্ষ্য করি,

#include<stdio.h>

int main()
{
    char ch;

    ch = getchar();

    printf("%c", ch);

return 0;
}

এই প্রোগ্রামটি রান করলে প্রোগ্রামটি কি বোর্ড থেকে একটি ক্যারেকটার ইনপুট নিবে এবং তাকে আউটপুট দিবে। লক্ষ্য করুন, কিভাবে getchar() এর রিটার্ন ভ্যালুকে ch ভ্যারিয়েবল এ এসাইন করা হয়েছে।

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

#include<stdio.h>

int main()
{
    printf("%c", getchar());

return 0;
}

এই প্রোগ্রামও একই ভাবে ইনপুট নিয়ে আউটপুট দিবে। এখানে প্রথমেই printf() ফাংশনকে কল করা হবে। এই ফাংশনের দ্বিতীয় আর্গুমেন্ট হিসেবে আছে getchar() ফাংশন কল, অর্থাৎ একটি ক্যারেকটার ইনপুট এর ইন্সট্রাকশন। তাই printf() ফাংশন রিটার্ন করার আগেই getchar() কে রিটার্ন আসতে হবে। আর getchar() রিটার্ন দিবে একটি ইন্টিজার ভ্যালু। এই ভ্যালুকে ক্যারেকটার হিসেবে প্রিন্ট করে তবেই printf() ফাংশন main() এ আবার ফেরত আসবে।

নিয়মিত অনুশীলন করলে এই সব ব্যাপার আস্তে আস্তে পরিষ্কার হয়ে যাবে।

এতক্ষণ আমরা একটি লাইব্রেরী ফাংশন নিয়ে কথা বললাম। এখন আসি সেই সব ইউজার ডিফাইন্ড ফাংশনের কথায় যারা ভ্যালু রিটার্ন দেয়। উপরে return এর ব্যবহার সংক্রান্ত একটি পোস্টের লিংক ছিলো। যারা পড়েন নাই তারা দয়া করে সেটা পড়ে আসেন।

একটি ইউজার ডিফাইন্ড ফাংশন লিখার সময় অবশ্যই তার রিটার্ন টাইপ নির্ধারণ করে দিতে হয়। যদি রিটার্ন টাইপ void না হয়, তাহলে সেই ফাংশনকে অবশ্যই নির্দিষ্ট করা টাইপের ভ্যালু কলিং ফাংশনকে রিটার্ন দিতে হবে। সাধারণত কোন ফাংশনের কাজ এর একদম শেষ ধাপে ভ্যালু রিটার্ন দেওয়া হয়। রিটার্ন ভ্যালু ফেরত পাঠানোর পরেই ফাংশনও তার কাজ থামিয়ে আবার কলিং ফাংশনে ফেরত আসে। আসুন আমরা একটি ইউজার ডিফাইন্ড ফাংশন লিখি যে ইউজার এর কাছ থেকে একটি নম্বর ইনপুট নিয়ে তার বর্গ কে কলিং ফাংশনে রিটার্ন দিবে। ধরা যাক, ফাংশনটির নাম হবে get_sqr()।

এখন, get_sqr() ফাংশনটির প্রোটোটাইপ লিখি। এটি তার কলিং ফাংশনকে একটি সংখ্যা ফেরত দিবে। তাই অবশ্যই এর রিটার্ন টাইপ হবে int। আর যেহেতু কলিং ফাংশন এই ফাংশনটিকে কোন ধরনের তথ্য দেওয়া ছাড়াই কল করবে তাই এর কোন প্যারামিটার লিস্ট থাকবে না, অর্থাৎ প্যারামিটার এর স্থানে হবে void। কাজেই,

int get_sqr (void);

এখন আমরা সম্পূর্ণ get_sqr() ফাংশনটি লিখবো। ফাংশনটি লিখার সময়, আমাদের মনে রাখতে হবে যে ফাংশনটি কয় ধাপে কাজ শেষ করবে।

১ম ধাপ, একটি নম্বর ইনপুট নিয়ে তার বর্গ বের করতে হবে। কাজেই ২ টি int টাইপের ভ্যারিয়েবল ডিক্লেয়ার করতে হবে ফাংশনের শুরুতেই। ধরি, এদের নাম হচ্ছে input এবং square।

২য় ধাপ, একটি নম্বর ইনপুট দেওয়ার জন্য ইউজারকে একটি মেসেজ দেওয়া হবে যা স্ক্রিনে প্রিন্ট হবে। তাই এটি একটি printf() ফাংশন কল।

৩য় ধাপ, কিবোর্ড থেকে একটি নম্বর input ভ্যারিয়েবলে ইনপুট নেওয়ার জন্য scanf() ইনপুট ফাংশন কল করতে হবে।

৪র্থ ধাপ, input এ রক্ষিত সংখ্যার বর্গ হিসাব করা ও তার মান কে square ভ্যারিয়েবলে জমা রাখা হবে।

৫ম ধাপ, যেহেতু আমাদের লক্ষ্য হচ্ছে get_sqr() ফাংশনটি বর্গের মানকে কলিং ফাংশনে রিটার্ন দিবে সেহেতু এই ধাপে আমরা square এ জমা রাখা সংখ্যাকে রিটার্ন দিবো।

আসুন নিচের প্রোগ্রমটি লক্ষ্য করি। এখানে main() ফাংশন get_sqr() কল করবে এবং তার রিটার্ন ভ্যালু প্রিন্ট করবে।

/* প্রোগ্রামের শুরু এখান থেকে*/

#include<stdio.h>

int get_sqr (void); /* get_sqr() ফাংশনের প্রোটোটাইপ */

int main()
{
    int output; /*get_sqr() ফাংশনের রিটার্ন ভ্যালু গ্রহন করার জন্য একটি ইন্টিজার ভ্যারিয়েবল ডিক্লেয়ার করা হল */

    output = get_sqr(); /* ফাংশন কল করা হল এবং তার রিটার্ন ভ্যালু output এ এসাইন করা হল */

    printf("the square is %d", output);

return 0;
}

int get_sqr (void) /* get_sqr() ফাংশন ডেফিনিশন শুরু */
{
    int input, square; /* ১ম ধাপ */
    printf("Enter a number: "); /* ২য় ধাপ */
    scanf("%d", &input); /*৩য় ধাপ*/
    square= input*input; /*৪র্থ ধাপ*/

return square; /* ৫ম ধাপ */
}

/* প্রোগ্রাম শেষ */

আশা করি এই উদাহরণ বুঝতে কারো কোন সমস্যা হবে না। কাজেই রিটার্ন ভ্যালু সহ কোন ফাংশন তৈরী বা ব্যবহারের সময় মনে রাখতে হবে যে,


  • ফাংশন তৈরীর ক্ষেত্রে, প্রোটোটাইপ ডিক্লেয়ারেশন ও মূল ফাংশন ডেফিনিশন, উভয়ের সময়ই ফাংশনটির রিটার্ন টাইপ উল্লেখ করতে হবে।
  • return value; আকারে value তে রক্ষিত ডেটা রিটার্ন করা যাবে। তবে অবশ্যই ডেটাকে পূর্বে ডিক্লেয়ার করা টাইপের হতে হবে।
  • void ফাংশন (void রিটার্ন টাইপের ফাংশন) এর ক্ষেত্রে কোন কিছুই রিটার্ন দেওয়া হবে না। তাই return স্টেটমেন্ট ব্যবহার না করেই বা শুধু return; ব্যবহার করেই ফাংশন শেষ করা যাবে। কোন অবস্থাতেই void ভিন্ন অন্য কোন টাইপের ফাংশনের ক্ষেত্রে শুধু return ; ব্যবহার করা ঠিক না।
  • ফাংশনের রিটার্ন ভ্যালু গ্রহনের জন্য কলিং ফাংশন এ সঠিক ডেটা টাইপের ভ্যারিয়েবল থাকতে হবে। এই ক্ষেত্রে এসাইনমেন্ট অপারেটর ব্যবহার করে ভ্যারিয়েবলে রিটার্ন ভ্যালু এসাইন করা যাবে। এমন কোন এক্সপ্রেশন যদি থাকে যেখানে রিটার্ন টাইপের ডেটা সরাসরি ব্যবহার করা সম্ভব, সেখানে ফাংশনটিকে সরাসরিও ব্যবহার করা যাবে। তবে সেটা না করাই ভালো।
  • কলিং ফাংশন যদি ফাংশনের রিটার্ন ভ্যালু গ্রহণ না করে তাহলে কোন ক্ষতি নেই। ভ্যালুটি স্রেফ হারিয়ে যাবে। কাজেই রিটার্ন ভ্যালু আছে এমন কোন ফাংশন কল করলেই যে তার রিটার্ন ভ্যালু আমাদের কাজে লাগাতে হবে এমন কোন কথা নেই। যদি আমাদের সেটা কাজে লাগে, তাহলে আমরা ব্যবহার করবো, আর না লাগলে সেটা উপেক্ষা করবো।


.৬ - প্যারামিটার যুক্ত ফাংশন : আর্গুমেন্ট সহ ফাংশন কল করা

কম্পিউটার কি ও কিভাবে কাজ করে?

প্রোগ্রামিং শুরু করার আগে, কম্পিউটার কি এবং তা কিভাবে কাজ করে সেটা সম্পর্কে জেনে নেওয়াটা ভালো।



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

কম্পিউটার হচ্ছে কাজের বুয়ার মত। সে আপনাকে অনেক কাজ করে দিবে, তবে তার জন্য আপনাকে বলে বলে দিতে হবে যে কি কি কাজ তার করতে হবে। নিজে থেকে সে কিছুই করবে না। হয় আপনি তাকে বলে দিবেন অথবা, অন্য কেউ আপনার হয়ে তাকে নির্দেশনা দিবে।

কম্পিউটার কি কি কাজ করতে পারে সেটা নিয়ে কথা না বাড়িয়ে, আসুন দেখি সে কিভাবে কাজ করে। যে কাজই সে করুক না কেন, তিনিটি পর্যায়ে সে সকল কাজ সম্পাদন করে।

১. ব্যবহার কারীর থেকে সে কিছু তথ্য নিবে (ইনপুট)
২. তথ্যগুলো সে প্রসেস করবে
৩. প্রসেস করার পরে ফলাফল সে আবার ব্যবহারকারীকে ফেরত দিবে (আউটপুট)






যত জটিল কাজই আপনি কম্পিউটার কে করতে দেখেন না কেন সে আসলে এই তিনটি কাজই করে।

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

এর পর হচ্ছে প্রসেসিং। ইনপুট নেওয়া তথ্য বিভিন্ন উপায়ে কম্পিউটার প্রসেস করে থাকে। সেন্ট্রাল প্রসেসিং ইউনিট (CPU) নামক অংশটি এই কাজ করে থাকে। প্রসেসিং মূলত বিভিন্ন ধরনের হিসাব নিকাশ।



এরপর হচ্ছে আউটপুট। প্রসেসিং এর ফলাফলটি ব্যবহারকারী কে ফেরত দেওয়ার নাম আউটপুট। স্ট্যান্ডার্ড আউটপুট ডিভাইস হচ্ছে কম্পিউটার মনিটর এর স্ক্রিন। এছাড়াও প্রিন্টার, স্পিকার, ডিস্ক ড্রাইভ ইত্যাদি ডিভাইসেও কম্পিউটার আউটপুট দিয়ে থাকে।

এখন প্রশ্ন হল, কম্পিউটার কিভাবে বোঝে যে কখন কোন কাজটি করতে হবে?

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

কম্পিউটার বাইনারী ভাষা ব্যবহার করে কাজ করে। যে ধরনের কম্পিউটার ই হোক না কেন সে শুধুমাত্র বাইনারী ভাষা বুঝতে পারে। মানুষের ব্যবহৃত ভাষা তার কাছে বোধ গম্য নয়। বাইনারী ভাষা হচ্ছে 0 আর 1 দিয়ে তৈরী একটি ভাষা।

বাইনারী ভাষায় কম্পিউটার ইনপুট গ্রহন করে, হিসাব করে, আউটপুট দেয়, তথ্য জমা রাখে।

আমরা মানুষেরা বাইনারী ভাষায় কাজ করতে অভ্যস্ত নই। অনেকে এই ভাষায় কাজ করতে পারেন, কিন্তু তাদের সংখ্যা খুবই নগণ্য। তাহলে আমাদের মত সাধারণ প্রোগ্রামার রা কিভাবে কম্পিউটার কে নির্দেশনা দিবো?

এই সমস্যা সমাধানের জন্যেই প্রোগ্রামিং ল্যাংগুয়েজ এর আবিষ্কার। প্রোগ্রামিং ল্যাংগুয়েজ এর মাধ্যমে আমরা আমাদের বোধগম্য ভাষায় নির্দেশনা লিখি। এরপর একটি অনুবাদক এর মাধ্যমে আমাদের নির্দেশনাগুলোকে কম্পিউটার এর বোধগম্য ভাষায় রূপান্তর করা হয়। সেই রূপান্তরিত নির্দেশনা অনুসারেই আসলে কম্পিউটার কাজ করে থাকে।

একেক প্রোগ্রামিং ল্যাংগুয়েজ এর জন্য এই অনুবাদক একেক রকম। এরা মূলত দুইটি প্রধান শ্রেনীতে বিভক্ত। কম্পাইলার আর ইন্টারপ্রেটার। এদের সম্পর্কে পরে আলোচনা করা হবে। তবে এইটুকু মাথায় রাখতে হবে যে, অনুবাদক বিভিন্ন প্রোগ্রামিং ল্যাংগুয়েজ এ লিখা নির্দেশনা বা প্রোগ্রামকে মেশিন ল্যাংগুয়েজ এ রূপান্তরিত করে দেয়।

মেমরি


কম্পিউটার মেমরি নিয়ে একটু আলোচনা না করলেই না। কোন তথ্য ইনপুট নেওয়া,  তাকে নিয়ে কাজ করা এবং তাকে আউটপুট দেওয়ার পুরোটা সময়ই তথ্যগুলোকে কোন না কোন জায়গায় রাখতে হয়। কম্পিউটার এর মেমরি হচ্ছে সেরকম একটি জায়গা।

কম্পিউটার এ তথ্য রাখার অনেকগুলো জায়গা রয়েছে। তবে মেমরি বলতে আমরা মূলত RAM কে বুঝাই। যে কোন প্রোগ্রাম তার কাজ সম্পাদন করার জন্য RAM এর জায়গা ব্যবহার করে থাকে।

কম্পিউটার এ তথ্য রাখার জায়গার একক হচ্ছে বিট (bit)। একটি বিটে একটি 0 অথবা একটি 1 থাকতে পারে। ৮ টি বিট নিয়ে একটি বাইট (byte) গঠিত হয়। অর্থাৎ কম্পিউটার মেমরিতে পরপর ৮ বিট জায়গাকে একত্রে ১ বাইট জায়গা বলা হয়। বাইটের গুরুত্ব হচ্ছে, একটি মেমরি বা RAM এর আকার যাই হোক না কেন তা ১ বাইট ১ বাইট করে আলাদা আলাদা এলাকায় বিভক্ত। একটু ব্যাখ্যা করি।

আমরা বর্গফুট, বর্গমিটার এককে ক্ষেত্রফল মাপি। কিন্তু জমি কেনা বেচার জন্য আমরা এইসব একক ব্যবহার না করে শতাংশ বা ডেসিমাল একক ব্যবহার করি। ১ ডেসিমাল হচ্ছে প্রায় ৪৩৬ বর্গফুট। ১ ডেসিমাল এর কম জমি কেনা বেচা করাটা হাস্যকর, কারণ এর কমে কোন জমিতে বাড়ি করা যায় না।

ঠিক একই ভাবে, যদিও বিট মেমরি মাপার ক্ষুদ্রতম একক, বাইট হচ্ছে মেমরি ব্যবহার করার কার্যকরী একক।



একটি মেমরি মডিউল বা RAM এর সম্পূর্ণ জায়গাটিই ১ বাইট করে অনেকগুলো এলাকায় বিভক্ত। এই প্রত্যেকটি এলাকারই একটি করে ঠিকানা থাকে যা একটি ধনাত্মক পূর্ণ সংখ্যা। এই ঠিকানা কে মেমরি এড্রেস বলে। বাইট হচ্ছে মেমরিতে ক্ষুদ্রতম স্থান যার নিজস্ব মেমরি এড্রেস আছে।

যে কোন তথ্যই যখন মেমরিতে রাখা হয় তখন তা তার আকার অনুযায়ী এক বা একাধিক বাইট জুড়ে থাকে। কম্পিউটার যখন তার মেমরিতে থাকা কোন তথ্য খুজে বের করে, তখন যে এই মেমরি এড্রেস ব্যবহার করে খোজার ও প্রসেস করার কাজ করে থাকে।

বাইট খুব ছোট একটি একক।

১০২৪ বাইটকে একত্রে ১ কিলোবাইট
১০২৪ কিলোবাইটকে একত্রে ১ মেগাবাইট
১০২৪ মেগাবাইট কে একত্রে ১ গিগাবাইট বলা হয়।

কাজেই আপনার কম্পিউটার এর র‍্যাম ২ গিগাবাইট (GB) বলতে আসলে বোঝায় যে, আপনার র‍্যামটি (১০২৪x১০২৪x১০২৪) টি ১ বাইট এলাকায় বিভক্ত যার প্রত্যেকটি এলাকার একটি করে মেমরি এড্রেস আছে।

C স্ট্রিং : ইনপুট আউটপুট

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



C স্ট্যান্ডার্ড ইনপুট ফাংশন scanf() এবং আউটপুট ফাংশন printf() ব্যবহার করে সরাসরি স্ট্রিং ইনপুট আউটপুট করা যায়। এছাড়াও ANSI C স্ট্যান্ডার্ড লাইব্রেরী তে স্ট্রিং ইনপুট এর জন্য gets() ও fgets() ফাংশন এবং আউটপুট এর জন্য puts() ও fputs() ফাংশন রয়েছে। এছাড়াও বেশ কিছু উপায়ে স্ট্রিং ইনপুট নেওয়া যায় যার সংক্ষিপ্ত আলোচনা এখানে করা হবে।

স্ট্রিং ইনপুট


  • scanf() ব্যবহার করে


scanf() এর মাধ্যমে স্ট্রিং ইনপুট নেবার জন্য %s টাইপ স্পেসিফিকেশন ব্যবহার করা হয়। আর আর্গুমেন্ট হিসেবে স্ট্রিং এর নামটি ব্যবহার করা হয়। মনে রাখতে হবে যে, scanf() এর আর্গুমেন্ট এর সাথে সচরাচর যেরকম & ব্যবহার করা হয়, স্ট্রিং এর ক্ষেত্রে স্ট্রিং এর নামের আগে কখনোই & ব্যবহার করা হয় না।

উদাহরণস্বরূপ, আমরা str নামের একটি স্ট্রিং ভ্যারিয়েবল (char array) ডিক্লেয়ার করি যাতে ২০ ক্যারেকটার দৈর্ঘ্যের একটি স্ট্রিং রাখা যাবে। এরপর আমরা তাতে scanf() ব্যবহার করে ইনপুট নিবো।

char str[21];

scanf("%s", str);

এই কোড দ্বারা আমরা ২০ ক্যারেকটার দৈর্ঘ্যের একটি স্ট্রিং ইনপুট নিতে পারবো। তবে তাতে কোন white space ক্যারেকটার (যেমন, blank space বা new line ক্যারেকটার) থাকতে পারবে না। এর কারণ হচ্ছে white space ক্যারেকটারকে scanf() সেপারেটর হিসেবে ধরে নেয়। যখনই ইনপুট এ কোন white space ক্যারেকটার পায়, তখনই সে যে ভ্যারিয়েবল এ ইনপুট নিচ্ছিলো তাতে ইনপুট নেওয়া বন্ধ করে দেয় এবং আর্গুমেন্ট লিস্টে পরবর্তী কোন ভ্যারিয়েবল এড্রেস থাকলে তাতে ইনপুট নেওয়া শুরু করে।

অর্থাৎ,  উপরের কোডে আমরা যদি "Programming" স্ট্রিং টি ইনপুট দিই তাহলে ঠিকমতো ইনপুট হবে কিন্তু, "I love C string" স্ট্রিংটি ইনপুট নিলে শুধু "I" ইনপুট হবে str স্ট্রিং এ। বাকি "love C string" অংশটি ইনপুট বাফারে রয়ে যাবে যা পরবর্তী কোন ইনপুট ফাংশন কর্তৃক ব্যবহৃত হবে।

তাহলে কি আমরা scanf() ব্যবহার করে সম্পূর্ণ লাইন ইনপুট নিতে পারবো না, যেখানে শব্দগুলোর মধ্যে blank space থাকবে? অবশ্যই পারবো। তবে তার জন্য "%s" স্পেসিফিকেশন এর পরিবর্তে "%[^\n]" স্পেসিফিকেশন ব্যবহার করতে হবে। যেমন, উপরের কোডটিই যদি আমরা এইভাবে লিখি তাহলেই এই সমস্যার সমাধান হয়ে যাবেঃ

char str[21];

scanf("%[^\n]", str);

এই কোডে ইনপুট এ new line ক্যারেকটার '\n' এর আগ পর্যন্ত যা আছে তার পুরোটাই str এ ইনপুট নিবে। তবে অবশ্যই str স্ট্রিং এ পর্যাপ্ত জায়গা থাকতে হবে। পর্যাপ্ত জায়গা না থাকলে স্ট্রিং এর ধারণক্ষমতা পর্যন্ত ইনপুট নেবার পরে, বাকি অংশ ইনপুট বাফারেই রয়ে যাবে, যা পরবর্তী কোন ইনপুট ফাংশন কর্তৃক ব্যবহৃত হবে।

স্ট্রিং সমাপ্তিজ্ঞাপক Null Terminator ('\0') টি scanf() কর্তৃক অটোমেটিকালি স্ট্রিং এর শেষে যুক্ত হয়ে যাবে। 

new line ক্যারেকটার ('\n') কে scanf() ইনপুট না নিয়ে ইনপুট বাফারে রেখে দেয়। তাই পর পর দুইটি স্ট্রিং ইনপুট নেওয়ার সময় সতর্কতা অবলম্বন করতে হবে। নিচের কোডটি রান করেন এবং তাতে "I love C" এবং "this is a string" স্ট্রিং দুইটি কিবোর্ড থেকে ইনপুট দিন। দেখেন রেজাল্ট কি হয়। আপনি কি রেজাল্ট টি ব্যাখ্যা করতে পারবেন?

/* উদাহরণ শুরু */
#include<stdio.h>

int main()
{
char str1[21], str2[21];

scanf("%[^\n]", str1);
scanf("%[^\n]", str2);

printf(str1);
printf(str2);

return 0;
}
/* উদাহরণ শেষ */

  • gets() ও fgets() ব্যবহার করে 


C স্ট্রিং ইনপুট নেওয়ার সবচে সহজ উপায় হচ্ছে gets() ফাংশন ব্যবহার করা। এতটাই সহজ যে, এই ফাংশনের আর্গুমেন্ট হিসেবে স্রেফ স্ট্রিং এর নামটি দিয়ে দিলেই ইনপুট হয়ে যায়। যেমন,

char str[21];

gets(str);

এই কোডটি new line ক্যারেকটার চাপার আগ পর্যন্ত যা ইনপুট বাফারে থাকবে তা str স্ট্রিং এ ইনপুট নিবে। তবে অবশ্যই স্ট্রিং এর ধারণক্ষমতার মধ্যে হতে হবে। যদি ধারণক্ষমতার অতিরিক্ত কোন ক্যারেকটার ইনপুট বাফারে থাকে তবে তা ইনপুট বাফারেই থাকবে যা পরবর্তী কোন ইনপুট ফাংশন কর্তৃক ব্যবহৃত হবে।

স্ট্রিং সমাপ্তিজ্ঞাপক Null Terminator ('\0') টি gets() কর্তৃক অটোমেটিকালি স্ট্রিং এর শেষে যুক্ত হয়ে যাবে। 

new line ক্যারেকটার ('\n') কে gets() ইনপুট নিয়ে নেয়। তাই পর পর দুইটি স্ট্রিং ইনপুট নেওয়ার সময় কোন সমস্যা হয় না। নিচের কোডটি রান করেন এবং তাতে "I love C" এবং "this is a string" স্ট্রিং দুইটি কিবোর্ড থেকে ইনপুট দিন। দেখেন রেজাল্ট কি হয়। আপনি কি রেজাল্ট টি ব্যাখ্যা করতে পারবেন? scanf() এর রেজাল্টের সাথে এর পার্থক্য কি?

/* উদাহরণ শুরু */
#include<stdio.h>

int main()
{
char str1[21], str2[21];

gets(str1);
gets(str2);

puts(str1);
puts(str2);

return 0;
}
/* উদাহরণ শেষ */

[Note : কিছু নিরাপত্তাজনিত কারণে, C এর আধুনিক স্পেসিফিকেশন এ gets() ফাংশন এর ব্যবহার রহিত করা হয়েছে। এই সম্পর্কে বিস্তারিত জানতে ও বুঝতে হলে আপনাকে C ভাষা সম্পর্কে খুব ভালো করে জানতে হবে। তাই, যদিও gets() এখনো ব্যবহার করা যায়, তবে আপনাদের প্রতি পরামর্শ থাকবে gets() ব্যবহার না করে অন্য কোন উপায়ে স্ট্রিং ইনপুট নিতে। C11 স্পেসিফিকেশন এ fget() ব্যবহার করতে বলা হয়েছে। এই ফাংশন সম্পর্কে জানার জন্য এখানে দেখুন।]

স্ট্রিং আউটপুট 

  • printf() ব্যবহার করে


স্ট্যান্ডার্ড আউটপুট ফাংশন printf() ব্যবহার করে দুইভাবে স্ট্রিং আউটপুট দেওয়া যায়। প্রথম পদ্ধতি হচ্ছে, স্ট্রিং এর নামকে সরাসরি printf() এর আর্গুমেন্ট হিসেবে ব্যবহার করে। যেমন,

char str[]= "I love strings.";

printf(str);

এই অংশটি I love strings. স্ট্রিংটি আউটপুট দিবে। তবে এই ক্ষেত্রে যদি আমরা আউটপুট এর পরে একটি new line ক্যারেকটার প্রিন্ট করতে চাই তাহলে আলাদা আরেকটি আউটপুট ফাংশন ব্যবহার করতে হবে।

দ্বিতীয় পদ্ধতি হচ্ছে, %s টাইপ স্পেসিফিকেশন ব্যবহার করে এবং স্ট্রিং এর নামকে সেকেন্ড আর্গুমেন্ট হিসেবে ব্যবহার করে। যেমন,

char str[]="I love strings.";

printf("%s", str);

এই ক্ষেত্রেও I love strings. স্ট্রিংটিই প্রিন্ট হবে। তবে এখানে আমরা প্রয়োজনমত new line ক্যারেকটার সংযোজন করতে পারবো, একাধিক স্ট্রিং একই আউটপুট ফাংশনে আউটপুট দিতে পারবো এবং স্ট্রিং এর সাথে অন্য ডেটা টাইপের ডেটাও আউটপুট দিতে পারবো।

  • puts() ও fputs() ব্যবহার করে


puts() ব্যবহার করে স্ট্রিং আউটপুট দেবার পদ্ধতি অনেকটা printf() ব্যবহার করে আউটপুট দেবার প্রথম পদ্ধতির মত। puts() এর আর্গুমেন্ট হিসেবে স্ট্রিং এর নাম দিয়ে দিলেই স্ট্রিং আউটপুট হয়। যেমন,

char str[]="I love strings.";

puts(str);

তবে printf() এর সাথে পার্থক্য হচ্ছে এখানে অটোমেটিক একটি new line ক্যারেকটার প্রিন্ট হবে। একটি puts() ব্যবহার করে কেবল ১ টি স্ট্রিং আউটপুট দেওয়া যাবে।

fgets() হচ্ছে gets() এর ফাইল আউটপুট ভার্সন। এটি সম্পর্কে বিস্তারিত জানার জন্যে এখানে দেখুন।

স্ট্রিং ইনপুট এর একটি বিকল্প উপায়ঃ

[শুধু মাত্র আগ্রহীরা এটা পড়বেন। এটা সবার পড়ার দরকার নাই।]

স্ট্রিং একটি ক্যারেকটার array। তাই এই array এর একটি ইন্ডেক্সে একটি করে ক্যারেকটার থাকে। আমরা খুব সহজেই ইনপুট বাফার থেকে একটি করে ক্যারেকটার নিয়ে একটি করে ইন্ডেক্সে রাখতে পারি এবং যখন new line ক্যারেকটার পাওয়া যাবে তখন Null terminator ('\0') আমরা ইন্ডেক্সে কপি করবো। যেমন,

char str[21], ch;
int i=0;

for (;;)
{
    ch=getchar();

    if (ch!='\n'&&i<21)
        str[i++]=ch;
    else
    {
        str[i]='\0';
        break;
    }
}

এটি দেখতে বেশ বড় হলেও এটি অনেক ক্ষেত্রে অনেক উপকারে আসে। 

CECP010 : শেয়ার বাজার ২.০

শেয়ার বাজারে টাকা আয়ের নিয়ম অন্য সব বাজারের মতই। তুমি একটা শেয়ার কম দামে কিনে বেশি দামে বিক্রি করবে। তবে সব সময় সেটা সম্ভব হয় না। অনেক সময় দেখা যায় যে কেনা দামের চেয়ে বাজার মূল্য কম। তখন এমন ভাবে বিক্রি করতে হয় যেন ক্ষতির পরিমান সর্ব নিম্ন হয়। উদাহরন দেই। লাভ-লোকসান লিমিটেড এর সাত দিনের শেয়ারের মূল্য নিন্ম রূপ:
দিন ১ ২ ৩ ৪ ৫ ৬ ৭
মূল্য ৩ ৮ ৪ ৫ ৬ ২ ৭

কাজেই কেউ যদি ১ম দিনে শেয়ার কিনে ২য় দিনে শেয়ার বিক্রি করে তাহলে তার লাভ হবে ৫ টাকা। আবার যদি ৬ষ্ঠ দিনে শেয়ার কিনে ৭ম দিনে বিক্রি করে তার লাভও ৫ টাকা। কাজেই এই সাত দিনের মধ্যে সবচেয়ে লাভজনক (ক্রয়, বিক্রয়) সমাবেশ হচ্ছে (১,২) ও (২, ৭)। মনে রাখতে হবে যে সমাবেশের উপাদান দুইটি হবে ক্রয়ের দিন ও বিক্রয়ের দিন। আবার যদি কেউ দ্বিতীয় দিনে শেয়ার কিনে থাকে, তাহলে এই সাত দিনের মধ্যে তার লাভ হবার কোন সম্ভাবনাই নাই। তবে সে যদি ৭ম দিনে শেয়ার বিক্রি করে তাহলে তার ১ টাকা ক্ষতি হবে যা সবচেয়ে কম ক্ষতি।
এমন একটি প্রোগ্রাম তৈরী করতে হবে যা নিচের শর্তের উপর ভিত্তি করে কয়েক দিনের শেয়ারের মূল্য ইনপুট হিসেবে নিয়ে সবচেয়ে লাভজনক বা সবচেয়ে কম ক্ষতির সমাবেশ গুলো আউটপুট হিসেবে দিবে:
১. কেনার পরের দিনই বিক্রি করা যাবে। যে দিন কেনা হয়েছে সেই দিন বিক্রি করা যাবে না।
২. শেয়ার বিক্রি করতে হলে আগে শেয়ার কিনতে হবে। কেনার আগে শেয়ার বিক্রি করা যাবে না।
৩. যদি প্রদত্ত মূল্য তালিকার মধ্যে শেয়ার কিনে লাভ করা না যায় তবেই কেবল মাত্র সবচেয়ে কম ক্ষতির সমাবেশ হিসাব করা যাবে।

 ইনপুট
প্রথম লাইনে একটি ইন্টিজার ইনপুট হবে যা কেস সংখ্যা (<=১০) নির্দেশ করবে। পরবর্তী লাইন থেকে কেস সংখ্যার সমান সংখ্যক লাইনে ইনপুট হবে।
প্রতি লাইনে শেয়ারের মূল্য সমূহ ইনপুট দেওয়া হবে (>=৭ এবং <=৩১ টি)। মূল্য দশমিকে হতে পারে। ইনপুট এর ক্রমানুসারে দিন হিসাব করা হবে। অর্থাৎ ইনপুট এর ১ম সংখ্যাটি ১ম দিনের দাম, ইনপুট এর nতম সংখ্যাটি nতম দিনের দাম প্রকাশ করবে।

আউটপুট
ইনপুট শেষ হবার পরে একটি ফাকা লাইন রেখে আউটপুট শুরু হবে। প্রতি লাইন আউটপুট এ ইনপুট কেস নাম্বার অনুযায়ী সবচেয়ে লাভজনক বা সবচেয়ে কম ক্ষতির সমাবেশ সমূহ থাকবে এইভাবে যেন (ক্রয়ের দিন, বিক্রয়ের দিন)। একাধিক সমাবেশ গ্রহণযোগ্য। এবং সবচেয়ে কম ক্ষতির সমাবেশ তখনই গ্রহণযোগ্য যখন লাভ একেবারেই সম্ভব নয়। ভাল মত বোঝার জন্য sample input / output দেখো।
কেস সংখ্যার সমান সংখ্যক লাইনে আউটপুট হবে।

প্রব্লেম সেটার: হাসিবুল হাসান হাওলাদার
 

 

C স্ট্যান্ডার্ড লাইব্রেরী : হেডার ফাইল সমূহ

C স্ট্যান্ডার্ড লাইব্রেরীতে যে সব হেডার ফাইল সমূহ বিদ্যমান তারা উক্ত ভাষায় প্রোগ্রামিং করার সময় ব্যবহৃত অনেক প্রিডিফাইন্ড ফাংশন, ম্যাক্রো ধ্রুবক ও ডেটা টাইপ এর ডেফিনিশন বহন করে।

C++ যেহেতু C এরই সুপার সেট, সেহেতু C++ লাইব্রেরীতেও এই হেডার ফাইল সমূহ বিদ্যমান, তবে কিছু কিছু ক্ষেত্রে পার্থক্য আছে। যেমন:

১. প্রত্যেকটি হেডার ফাইলের নাম C হেডার ফাইলের মতই, তবে নামের শুরুতে 'c' যুক্ত হবে এবং শেষে '.h' ফাইল নেম এক্সটেনশন থাকবে না। উদাহরণস্বরূপ C এর হেডার ফাইল <stdlib.h> কে C++ এ <cstdlib> হিসেবে লিখা হয়।

২. C++ এ namespace এর ধারণা বিদ্যমান, যেটা C তে অনুপস্থিত। C এর অনুরূপ সকল C++ হেডারের সব উপাদানই 'std' নেমস্পেস এ ডিফাইন করা।

তবে C এর সাথে মানিয়ে নেবার জন্য, ট্রেডিশনাল হেডার ফাইলও (যেমন, stdlib.h) C++ লাইব্রেরীতে থাকে, যদিও C++ এ তাদের ব্যবহার বাঞ্ছনীয় নয়।

৩. wchar_t, char16_t, char32_t and boo হচ্ছে C++ এর মৌলিক ডেটা টাইপ। তাই C হেডারে এই টাইপগুলো ডিফাইন করা থাকলেও একই C++ হেডারে এইগুলো ডিফাইন করা থাকে না।  একই কথা <iso646.h> হেডারে উপস্থিত কিছু ম্যাক্রো ধ্রুবকের ক্ষেত্রেও প্রযোজ্য, যারা C++ এ কিওয়র্ড হিসেবে বিদ্যমান।

৪. নিচের ফাংশনগুলোর ডিক্লেয়ারেশন এ প্যারামিটার এর কিছুটা ভিন্নতা আছে C++ এ:

strchr, strpbrk, strrchr, strstr, memchr

<cstdlib> হেডারে ডিফাইন করা at_exit, exit and abort এর কিছু অতিরিক্ত ফিচার আছে C++ এ। Overloading এর ধারণা কেবল C++  এ আছে, তাই কিছু কিছু ফাংশনের ওভারলোডেড ভার্সন C++ এ বিদ্যমান যারা অতিরিক্ত/ভিন্ন টাইপের কিছু প্যারামিটার নিতে পারে, তবে একই ধরনের কাজ করে। যেমন, <cmath> হেডার ফাইলের ফাংশনগুলোর float and long double ভার্সন C হেডার ফাইল <math.h> এ অনুপস্থিত।  ঠিক তেমনি <cstdlib> এ abs and div এর long ভার্সন বিদ্যমান, যা <stdlib.h> এ অনুপস্থিত।

আমাদের আলোচনায় যে সব ফাংশন, ম্যাক্রো বা টাইপ কেবল C++ এ ব্যবহার যোগ্য, C তে নয় তাদের নামের পাশেই সেটা চিহ্নিত করা থাকবে।

আসুন এবার আমরা C লাইব্রেরীর হেডার ফাইল ও তাদের সংক্ষিপ্ত কাজের তালিকা দেখি।

ANSI C স্ট্যান্ডার্ড লাইব্রেরী



  • <assert.h> : ডায়াগনস্টিক লাইব্রেরী 
  • <ctype.h> : ক্যারেক্টার ক্লাস টেস্ট বা ক্যারেকটার নিয়ে কাজ করার লাইব্রেরী 
  • <errno.h> : এরর বা ত্রুটি বিষয়ক লাইব্রেরী
  • <float.h> : ফ্লোটিং পয়েন্ট ডেটা টাইপ সমূহের বিভিন্ন ধর্ম ও সীমা নির্ধারক লাইব্রেরী
  • <limits.h> : ইন্টিজার ডেটা টাইপ সমূহের বিভিন্ন ধর্ম ও সীমা নির্ধারক লাইব্রেরী
  • <locale.h> : লোকালাইজেশন (স্থান, কাল ও প্রথাগত বিভিন্ন পূর্বনির্ধারিত মান ও চিহ্ন) লাইব্রেরী 
  • <math.h> : গাণিতিক অপারেশন নিয়ন্ত্রক লাইব্রেরী
  • <setjmp.h> : নন লোকাল জাম্প লাইব্রেরী
  • <signal.h> : সিগনাল হ্যান্ডেল করার লাইব্রেরী
  • <stdarg.h> : অনির্দিষ্ট আর্গুমেন্ট ব্যবস্থাপনাকারী লাইব্রেরী 
  • <stddef.h> : স্ট্যান্ডার্ড ডেফিনিশন লাইব্রেরী 
  • <stdio.h> : স্ট্যান্ডার্ড ইনপুট ও আউটপুট লাইব্রেরী 
  • <stdlib.h> : স্ট্যান্ডার্ড ইউটিলিটি লাইব্রেরী 
  • <string.h> : C স্ট্রিং লাইব্রেরী 
  • <time.h> : সময় ও তারিখ বিষয়ক লাইব্রেরী


ISO90 C স্ট্যান্ডার্ড লাইব্রেরী


ANSI C লাইব্রেরীতে নিচের হেডারটি যুক্ত হয়েছেঃ


  • <iso646.h> : ISO646 নির্দেশনা অনুসারে কিছু অপারেটর এর পরিবর্তিত রূপ নির্ধারক লাইব্রেরী


ISO99 C স্ট্যান্ডার্ড লাইব্রেরি


ISO90 C স্ট্যান্ডার্ড লাইব্রেরী এর সাথে নিচের হেডারগুলো যুক্ত হয়েছেঃ


  • <stdbool.h> : C তে boolean ডেটা টাইপ ব্যবহারের জন্য
  • <stdint.h> : নতুন কিছু ইন্টিজার টাইপ ডেফিনিশন লাইব্রেরী 
  • <uchar.h> : ইউনিকোড ক্যারেকটার লাইব্রেরী 
  • <wchar.h> : ওয়াইড ক্যারেকটার লাইব্রেরী
  • <wctype> : ওয়াইড ক্যারেকটার ক্লাস টেস্ট বা ওয়াইড ক্যারেকটার নিয়ে কাজ করার লাইব্রেরী 




C স্ট্যান্ডার্ড ইউটিলিটি লাইব্রেরী : STDLIB.H

C হেডার ফাইল: <stdlib.h>
C++ হেডার ফাইল: <cstdlib>

এই হেডার ফাইলে সাধারণ কিছু কর্ম সম্পাদনে প্রয়োজন এমন কিছু ফাংশন, কিছু ম্যাক্রো ধ্রুবক আর কিছু ইউজার ডিফাইন্ড ডেটা টাইপ ডিফাইন করা আছে। বিভিন্ন রূপান্তর, ডায়নামিক মেমরি ব্যবস্থাপনা, সার্চিং এবং সর্টিং, র‍্যান্ডম নাম্বার তৈরি এবং প্রোগ্রাম এনভায়রনমেন্ট এর সাথে সম্পর্কিত ফাংশন সমূহ এই হেডার ফাইল ব্যবহার করে প্রয়োগ করা যায়।

[ নিচের সব ফাংশন ANSI C এবং ANSI C++ এ ব্যবহার করা যায় না। অনেক ফাংশনই কেবল মাত্র নতুনতর স্ট্যান্ডার্ড এ ব্যবহার করা হয় (C++11)]

ফাংশনসমূহঃ

স্ট্রিং রূপান্তর (conversion):



  • atof: স্ট্রিং থেকে double এ রূপান্তর
  • atoi: স্ট্রিং থেকে integer এ রূপান্তর
  • atol: স্ট্রিং থেকে long int এ রূপান্তর
  • atoll: স্ট্রিং থেকে long long int এ রূপান্তর
  • strtod: স্ট্রিং থেকে double এ রূপান্তর
  • strtof: স্ট্রিং থেকে float এ রূপান্তর
  • strtol: স্ট্রিং থেকে long int এ রূপান্তর
  • strtold: স্ট্রিং থেকে long double এ রূপান্তর
  • strtoll: স্ট্রিং থেকে long long int এ রূপান্তর
  • strtoul: স্ট্রিং থেকে unsigned long int এ রূপান্তর
  • strtoull: স্ট্রিং থেকে unsigned long long int এ রূপান্তর


র‍্যান্ডম নাম্বার (Pseudo-random sequence) তৈরি:



  • rand: র‍্যান্ডম নাম্বার তৈরি করে
  • srand: rand() ফাংশনকে ইনিশিয়ালাইজ করে


ডায়নামিক মেমরি ব্যবস্থাপনাঃ



  • calloc: নির্দিষ্ট আকারের মেমরি ব্লক বরাদ্দ করণ (allocation) ও তাকে ইনিশিয়ালাজেশন করা
  • free: পূর্বে বরাদ্দকৃত মেমরি ব্লক অবমুক্ত করণ (deallocation)
  • malloc: নির্দিষ্ট আকারের মেমরি ব্লক বরাদ্দ করণ
  • realloc: পূর্বে বরাদ্দকৃত মেমরি ব্লক এর আকার পরিবর্তন করে তাকে পুনঃবরাদ্দ করণ


প্রোগ্রাম এনভায়রনমেন্ট সম্পর্কিতঃ



  • abort: চলমান কোন process কে বন্ধ করে দেওয়া
  • atexit: exit() ফাংশন ব্যবহার করা হলে কোন নির্দিষ্ট ফাংশনকে এক্সেকিউট করার জন্য
  • at_quick_exit: quick_exit() ফাংশন ব্যবহার করা হলে কোন নির্দিষ্ট ফাংশনকে এক্সেকিউট করার জন্য
  • exit: কোন প্রোগ্রামের কাজ তাৎক্ষণিক ভাবে থামিয়ে দেওয়ার জন্য
  • getenv: এনভায়রনমেন্ট সম্পর্কে তথ্যযুক্ত স্ট্রিং লাভের জন্য
  • quick_exit: কোন প্রোগ্রামের কাজ তাৎক্ষণিক ভাবে দ্রুত থামিয়ে দেওয়ার জন্য
  • system: অপারেটিং সিস্টেমে ব্যবহৃত হয় এমন কোন কমান্ড ব্যবহারের জন্য
  • _Exit: কোন প্রোগ্রামের কাজ তাৎক্ষণিক ভাবে থামিয়ে দেওয়ার জন্য


সার্চিং ও সর্টিং



  • bsearch: Array তে বাইনারি সার্চের জন্য
  • qsort: Array উপাদান সজ্জিতকরণ (sort) এর জন্য


ইন্টিজার এরিথমেটিক



  • abs: পরম মান বের করার জন্য
  • div: দুটি ইন্টিজারের ভাগফল ও ভাগশেষ বের করার জন্য
  • labs: পরম মান বের করার জন্য (long int)
  • ldiv: দুটি ইন্টিজারের ভাগফল ও ভাগশেষ বের করার জন্য (long int)
  • llabs: পরমমান বের করার জন্য (long long int)
  • lldiv: দুটি ইন্টিজারের ভাগফল ও ভাগশেষ বের করার জন্য (long long int) [C++11]


মাল্টি বাইট ক্যারেকটারঃ



  • mblen: মাল্টি বাইট ক্যারেকটার এর বাইট লেন্থ/ দৈর্ঘ্য বের করা
  • mbtowc: মাল্টিবাইট অনুক্রমকে (sequence) ওয়াইড ক্যারেকটার এ রূপান্তর 
  • wctomb: ওয়াইড ক্যারেকটার কে মাল্টিবাইট অনুক্রমে (squence) রূপান্তর


মাল্টি বাইট স্ট্রিংঃ



  • mbstowcs: মাল্টিবাইট ক্যারেকটার স্ট্রিং থেকে ওয়াইড ক্যারেকটার স্ট্রিং এ রূপান্তর 
  • wcstombs: ওয়াইড ক্যারেকটার স্ট্রিং থেকে মাল্টিবাইট ক্যারেকটার স্ট্রিং এ রূপান্তর 


ম্যাক্রো ধ্রুবক সমূহঃ



  • EXIT_FAILURE: exit() ফাংশন এর আর্গুমেন্ট (ব্যর্থ সমাপ্তির ক্ষেত্রে)
  • EXIT_SUCCESS: exit() ফাংশনের আর্গুমেন্ট (সফল সমাপ্তির ক্ষেত্রে)
  • MB_CUR_MAX: মাল্টিবাইট ক্যারেকটার এর সর্বোচ্চ আকার নির্দেশক 
  • NULL: নাল পয়েন্টার
  • RAND_MAX: rand() ফাংশন কর্তৃক তৈরি হওয়া সর্বোচ্চ সংখ্যা


ইউজার ডিফাইন্ড ডেটা টাইপ



  • div_t: div() ফাংশনের রিটার্ন টাইপ
  • ldiv_t: ldiv() ফাংশনের রিটার্ন টাইপ
  • lldiv_t: lldiv() ফাংশনের রিটার্ন টাইপ
  • size_t: Unsigned integer

সার্চ পদ্ধতি সমূহ

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



কিভাবে ডেটা সাজানো আছে এবং কোন পদ্ধতিতে ডেটা সার্চ করা হচ্ছে, তার উপর প্রোগ্রামের পারফর্মেন্স অনেকাংশে নির্ভর করে। আজকের আলোচনায় আমরা মৌলিক কিছু সার্চ টেকনিক সম্পর্কে সাধারণ আলোচনা করবো।

সাধারণ সার্চ টেকনিক সমূহ

এই সার্চ টেকনিকগুলো সম্পর্কে জানা ও বোঝার জন্য array, relational operator, logical operator এবং C প্রোগ্রাম কন্ট্রোল স্টেটমেন্ট সমূহ সম্পর্কে জ্ঞান থাকতে হবে।

n সংখ্যক তথ্য বিশিষ্ট একটি তালিকার কথা কল্পনা করি যেখানে প্রত্যেকটি তথ্যই একটি key হতে পারে। আমাদের লক্ষ্য হবে এই তালিকা থেকে যে কোন একটি নির্দিষ্ট key কে যতটা কম সম্ভব সময়ের মধ্যে খুজে বের করা। একটি তালিকা থেকে এভাবে খুঁজে বের করার জন্য আমাদের সতর্কতার সাথে লক্ষ্য করতে হবে যে, তালিকাটিতে ডেটা কিভাবে সাজানো রয়েছে, অর্থাৎ কোন ধরনের ডেটা স্ট্রাকচার ব্যবহার করা হয়েছে। প্রাথমিক ভাবে আমাদের সবার পরিচিত array ডেটা স্ট্রাকচারে তথ্য রাখা হয়েছে বলেই ধরে নিই। array তে কোন তথ্য দুইভাবে সাজানো থাকতে পারে। সুবিন্যস্ত  (sorted) এবং অবিন্যস্ত (unsorted)। আমরা প্রথমে এই দুই ক্ষেত্রে কিভাবে সার্চ করা হবে সেটা দেখবো। সাজানোর পদ্ধতি বা সর্টিং টেকনিক সম্পর্কে আলোচনার জন্য এইখানে দেখুন।

লিনিয়ার সার্চ ও বাইনারী সার্চ



১. লিনিয়ার সার্চ বা সিকোয়েন্সিয়াল সার্চ


এই সার্চ পদ্ধতি একেবারেই সরল ও সোজাসুজি পদ্ধতি। একটি array এর প্রথম ইন্ডেক্স থেকে সার্চ শুরু করবো এবং যতক্ষন পর্যন্ত key এর সাথে মিল পাওয়া না যাবে ততক্ষণ সার্চ চালিয়ে যাবো। এই ক্ষেত্রে সর্বোচ্চ শেষ ইন্ডেক্স পর্যন্ত সার্চ করার প্রয়োজন হতে পারে, যদি key টি শেষ ইন্ডেক্সে থাকে অথবা key টি আদৌ array তে না থেকে থাকে।

বর্ণনা থেকেই বোঝা যাচ্ছে যে বড় ডেটার ক্ষেত্রে এটি মন্থর গতির সার্চ। তবে সময় সাপেক্ষ হলেও অবিন্যস্ত  array এর ক্ষেত্রে এটিই একমাত্র সরাসরি সার্চ টেকনিক। এই বিষয়ে বিস্তারিত জানার জন্য এখানে দেখুন।


২. বাইনারি সার্চ


সুবিন্যস্ত array এর ক্ষেত্রে এই সার্চ টেকনিক ব্যবহার করা যায়। ধরা যাক একটি array এর সকল তথ্য ঊর্ধ্বক্রমে সাজানো আছে। অর্থাৎ প্রথম ইন্ডেক্সে সবচে ছোট আর শেষ ইন্ডেক্সে সবচে বড় মানের তথ্যটি আছে। এইখানে সার্চ শুরু করা হয় array এর মধ্য ইন্ডেক্স থেকে। যদি মধ্য ইন্ডেক্সের তথ্যের মান key এর চেয়ে কম হয় তাহলে সার্চ করা হয় array এর ডান পাশের অর্ধেকের মধ্য ইন্ডেক্সটি। আর যদি মান key এর চেয়ে বেশি হয় তাহলে সার্চ করা হয় array এর বাম পাশের অর্ধেকের মধ্য ইন্ডেক্সটি।

এভাবে প্রতিবারে array এর সার্চ এলাকা অর্ধেক হতে থাকে। তাই এটি লিনিয়ার সার্চ অপেক্ষা দ্রুতগতির। তবে এটি কেবলমাত্র সুবিন্যস্ত তথ্যের ক্ষেত্রে কাজ করে। অবিন্যস্ত তথ্যের উপর বাইনারি সার্চ চালানোর জন্য তাকে প্রথমে বিন্যস্ত করে বা সর্ট করে নেবার দরকার পরে। বিস্তারিত জানার জন্যে এখানে দেখুন।

কিছু উচ্চতর সার্চ টেকনিক


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

৩. হ্যাশ সার্চ


হ্যাশ টেবিলে সার্চ করা খুবই দ্রুতগতির। key এর হ্যাশ ভ্যালু বের করে হ্যাশ ইন্ডেক্স সার্চ করতে থাকলেই দ্রুত তথ্য খুজে পাওয়া যায়, অথবা বোঝা যায় যে তথ্যটি তালিকাতে নেই।

বিস্তারিত জানার জন্য এখানে দেখুন।

৪. বাইনারি ট্রি সার্চ


বাইনারি ট্রি সার্চও হ্যাশ সার্চের মতই তবে এটি সাধারণত তুলনামূলক ভাবে মন্থর, বিশেষ করে যদি ট্রি এর সজ্জা ঠিকমতো ব্যালেন্স করা না থাকে।

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

বিস্তারিত জানার জন্য এখানে দেখুন।