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

অ্যারে(array)

ধরা যাক, আমরা ১ থেকে ১০ পর্যন্ত সংখ্যাগুলো যোগ করব; তাহলে আমাদেরকে কি করতে হবে? আমরা দশটা ভেরিয়েবল নিয়ে সেটা এক এক করে যোগ করতে পারি। এই প্রোগ্রামটি যদি আমরা সি বা সি++ এ লিখি তাহলে কেমন হবে?

/******************************************************************************

Author: Shahinur
Description: This program is to add number from 1 to 10 without using array

*******************************************************************************/

#include <iostream>
using namespace std;

int main() {
 int sum=0;
 int a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10;
 
 sum=a+b+c+d+e+f+g+h+i+j;
 
 cout<<sum;
 
 return 0;
}

হয়তো এই প্রোগ্রামটা দেখে কারো কাছে অসুবিধা মনে হচ্ছেনা। কিন্তু যদি আমরা ১ থেকে ১০০ বা ১০০০ পর্যন্ত যোগ করতে চাই, তাহলে কেমন হবে? আমরা কি ঐ সংখ্যক ভ্যারিয়েবল ডিক্লেয়ার করব? হ্যা, করতে পারি; কিন্তু সেটা কখনোই যুক্তিযুক্ত নয়। আর তাই এই সমস্যা থেকে উত্তোরণের জন্যই অ্যারের উৎপত্তি।
অর্থাৎ, অ্যারে হচ্ছে একই প্রকার ডাটার সমষ্টি। আমাদের যখন একই প্রকার ডাটা টাইপের অনেকগুলো ভেরিয়েবল ব্যবহার প্রয়োজন পড়বে তখন অ্যারে ব্যবহার করব। অ্যারেতে একটা নির্দিষ্ট ইনডেক্স নাম্বার থাকে যার মাধ্যমে ঐ অ্যারের নির্দিষ্ট কোন উপাদানকে নির্দেশ করা হয়ে থাকে। ধরা যাক a[10] একটি অ্যারে যার উপাদান সংখ্যা ১০, তাহলে a[0] এই সিরিজের প্রথম উপাদানকে নির্দেশ করবে। এখেনে মনে রাখা দরকার, অ্যারের ইনডেক্স সবসময় ০ থেকে শুরু হয়। উপরের প্রোগ্রামটা যদি আমরা অ্যারে দিয়ে করি তাহলে হবে –

/******************************************************************************

Author: Shahinur
Description: This program is to add number from 1 to 10 using array

*******************************************************************************/

#include <iostream>
using namespace std;

int main() {
 int sum=0;
 int a[10];
 a[0]=1,a[1]=2,a[2]=3,a[3]=4,a[4]=5,a[5]=6,a[6]=7,a[7]=8,a[8]=9,a[9]=10;
 
 sum=a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9];
 
 cout<<sum;
 
 return 0;
}

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

/******************************************************************************

Author: Shahinur
Description: This program is to add number from 1 to 10 using array

*******************************************************************************/
#include <iostream>
using namespace std;

int main() {
	int sum=0;
	int a[10];
        for(int i=0;i<10;i++)
          {
    	   cin>>a[i];
          }
	
	for(int i=0;i<10;i++)
           {
    	   sum+=a[i];
           }
	
	cout<<sum;
	
	return 0;
}

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

অ্যারের বিভিন্ন জটিল প্রয়োগ আছে, তবে আমরা এখন সেই আলোচনায় যাবনা।

পয়েন্টার(Pointer)

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

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

এখন আমরা পয়েন্টার ব্যবহার করে একটি প্রোগ্রাম দেখে নেই – 

/******************************************************************************

Author: Shahinur
Description: This Program demonstrate the pointer in C++

*******************************************************************************/
#include <iostream>
using namespace std;

int main()
{
    int val1=5, val2=10;
    int *p1, *p2;
    
    p1=&val1;
    p2=p1;
    cout<<p1<<endl<<*p2<<endl<<p2<<endl<<*p1;

    return 0;
}


আমার ক্ষেত্রে আউটপুট টা এমন –

0x7fff4d0af138
5
0x7fff4d0af138
5

এখানে দেখতে পাচ্ছি একবার একটা এড্রেস প্রিন্ট হয়েছে এবং অন্যবার একটা ভ্যালু প্রিন্ট হয়েছে যেটা আমরা val1 এ রেখেছিলাম। এবং পরে একই ঘটনা পুনরাবৃত্তি ঘটেছে। মূলত এখানে যে এড্রেসটা দেখাচ্ছে সেটা ‘৫’ ভ্যালুটা যে এড্রেসে সংরক্ষিত আছে সেটার এড্রেস। আমার ক্ষেত্রে যে ভ্যালুটা দেখাচ্ছে সেটা কিন্তু আপনার ক্ষেত্রে দেখাবে না, ভিন্ন একটা এড্রেস দেখাবে। কারণ কি? কারণ হচ্ছে, মেমরি এক এক সময় এক এক জায়গা দখল করে। আমরা যদিও কোন ভেরিয়েবলের জন্য বারবার একই ভ্যালু দেখি, প্ররকৃতপক্ষে কম্পিউটারের মেমরিতে ভিন্ন ভিন্ন জিনিস ঘটে। অনেক মজার ঘটানা, তাই না?

এখন আসি আমাদের আউটপুট কেন এমন হল সেটা একটু আলোচনা করা যাক – 

কোন পয়েন্টার ভেরিয়েবলকে ডিক্লেয়ার করতে হলে * চিনহ ব্যবহার করতে হয়। আমরা লাইন নম্বর ১২ তে p1 এবং p2 নামে দুইটা পয়েন্টার ডিক্লেয়ার করেছি। 

তারপর val1 এর যে এড্রেসটা আছে সেটাকে পয়েন্টার p1 এ এসাইন করেছি। এখানে বলে রাখা ভাল, কোন ভেরিয়েবলের এড্রেস কে এক্সেস করতে হলে তার আগে & সাইন দিতে হয়। ১৪ নম্বর লাইনে আমরা যদি & সাইনটা না দিতাম তাহলে আমাদের প্রোগ্রামটা ভূল হত। কেন ভূল হত? একটু চিন্তা করে দেখেন ত বের করতে পারেন কিনা? আচ্ছা আমি বলে দিচ্ছি। এখানে পয়েন্টার p1 একটা এড্রেস, আর ভেরিয়েবল val1 একটা ভ্যালু। আর প্রোগ্রামিং এ সবসময় একই ধরনের ডাটা টাইপের তুলনা বা ম্যাথমেটিক্যাল অপারেশন করা যায়, যেটা ভিন্ন টাইপের ক্ষেত্রে হয়না।

পরের লাইনে আমরা p2 তে p1 টা এসাইন করেছি। এখানে নরমাল এসাইনমেন্ট অপারেটর দিয়েই কাজ হয়ে গেছে। কারণ তারা দুইটাই একই টাইপের।

পরে যখন আমরা p1 প্রিন্ট দিলাম তখন একটা এড্রেস প্রিন্ট দিয়েছে, আবার যখন *p1 প্রিন্ট দিলাম তখন সেটা ঐ p1 এর এড্রেসে যে ভ্যালু ছিল সেটা প্রিন্ট দিয়েছে। অর্থাৎ কোন পয়েন্টার এর ভ্যালু প্রিন্ট দিতে হলে আমাদেরকে * এই স্টার চিনহটি দিতে হবে।

একইভাবে আমরা যেহেতু p1 কে p2 তে এসাইন করেছি, তাই p1 এর সমস্ত ভ্যালু p2 তে কপি হয়ে গেছে। বাকিটুকু আপনারা নিজেরাই বুঝতে পারবেন আশা করি।

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

ধন্যবাদ 🙂