উদাহরণ দিয়ে বললে হয়ত ভালো বুঝতে পারবে। আমি একটা সি প্রোগ্রাম লিখতে চাই যার মুখ্য কাজ হচ্ছে, একটা ক্লাসের সকল ছাত্র গণিত পরীক্ষায় অংশগ্রহণ করেছে এবং তাদের সকলের গড় নম্বর বের করা। ধর, ক্লাসে যদি ৩ টি ছাত্র থাকে, আর তাদের মার্কস যদি যথাক্রমে ৭০, ৮০ এবং ৯০ হয়, তবে তাদের গড় নম্বর
(৭০ + ৮০ + ৯০) / ৩ = ৮০ । তাহলে, এর জন্য আমাকে যা করতে হবে তা হল, নম্বর তিনটা আলাদা আলাদা ভ্যারিয়েবল এ জমা রেখে যোগফল বের করতে হবে, আর তারপরে তাদের গড় বের করতে হবে, ভাগ করে। প্রোগ্রামটি হবে নিচের মত।
#include<stdio.h>
int main()
{
int a,b,c;
a = 70;
b = 80;
c = 90;
int sum = a+b+c;
int avg = sum/3;
printf("%d", avg);
return 0;
}
গড় যেহেতু দশমিক হতে পারে তাই ভ্যারিয়েবলগুলো double বা float নেওয়া উচিত ছিল। কিন্তু যেহেতু শুধু বুঝানোর স্বার্থে উদাহরণ দিচ্ছি, তাই এই ছোট ডিটেইলস গুলো বাদ দিলাম। আচ্ছা, তো এই প্রোগ্রামে আমি তিনটা স্টুডেন্ট এর পরীক্ষার মার্কস জমা রাখার জন্য তিনটা ভ্যারিয়েবল নিয়েছি। কিন্তু আমার ক্লাসে যদি ৩ টা না হয়ে ৫০ টা স্টুডেন্ট থাকত, তাহলে আমাকে এরকম ৫০ টা ভ্যারিয়েবল নিতে হত, যেটা খুবই শ্রমসাপেক্ষ। আবার এতগুলো ভ্যারিয়েবল এর জন্য আলাদা আলাদা নাম বের করাও কঠিন। হঠাত করে কেউ যদি তোমাকে জানতে চায় যে, ৭ রোলের পরীক্ষায় মার্কস কত, তখন এটা মনে করতেও তোমার হিমশিম খেতে হত যে, ৭ রোলের মার্কস তুমি কোন ভ্যারিয়েবল এ সেইভ করেছ। এরকম সিচ্যুয়েশান মানে, একই ধরনের অনেকগুলো ভ্যারিয়েবল যখন আমাদের ক্রিয়েট করতে হবে, তখন আমাদের অ্যারে প্রয়োজন হবে।
#include<stdio.h>
int main()
{
int st[5];
st[0] = 56;
st[1] = 62;
st[2] = 33;
st[3] = 25;
st[4] = 84;
int sum = st[0] + st[1] + st[2] + st[3] + st[4];
int avg = sum/5;
printf("%d\n", avg);
return 0;
}
উপরের প্রোগ্রামটা আমি অ্যারে দিয়ে করেছি। এখানে আমি ক্লাসের স্টুডেন্ট সংখ্যা ধরেছি ৫ জন। আগে আমরা ৫ টা স্টুডেন্টের মার্কস রাখার জন্য ৫ টা আলাদা আলাদা ভ্যারিয়েবল নিতাম নিচের মত করে।
int a,b,c,d,e;
a = 56;
b = 62;
c = 33;
d = 25;
e = 84;
কিন্তু এখন যেহেতু আমরা অ্যারে ব্যবহার করছি, আমাদের আলাদা আলাদা করে ভ্যারিয়েবল নেওয়া লাগবে না, আমাদের শুধু ৫ সাইজের একটা ইন্টিজার অ্যারে নিলেই হবে। যে একাই ৫ জনের মার্কস রাখতে সক্ষম। আমরা ৫ সাইজের ইন্টিজার অ্যারে ডিক্লিয়ার করি নিচের মত করে।
int st[5];
শুরুতে, টাইপ(ইন্টিজার, ডাবল ইত্যাদি), তারপর অ্যারের নাম এবং সবশেষে থার্ড ব্র্যাকেটে অ্যারের সাইজ(কতগুলো আইটেম জমা রাখতে হবে, যেহেতু ৫ জনের মার্কস রাখতে হবে তাই সাইজ ৫)। আলাদা ৫ টি ভ্যারিয়েবলের তুলনায় এই পদ্ধতির অনেক সুবিধা আছে। একটা একটা করে ব্যাখ্যা দিচ্ছি।
প্রথমত, আমাদের আলাদা ৫ টি নাম প্রয়োজন হচ্ছে না। আগে ৫ টি ভ্যারিয়েবল নিতে হলে আমাদের a, b, c, d, e এরকম বা অন্য ৫ টি নাম নিতে হত। কিন্তু এখন অ্যারের জন্য একটা নাম নিলেই সেই হিসেবে সি নিজেই ৫ টি ভ্যারিয়েবলের নামকরণ করে ফেলছে। যেমন, আমি অ্যারের নাম নিয়েছি st, তাই সি নিজেই আমার জন্য ৫ টি ভ্যারিয়েবল তৈরী করেছে, যাদের নাম – st[0], st[1], st[2], st[3] এবং st[4]। এই যে ভ্যারিয়েবলের নাম গুলোতে থার্ড ব্র্যাকেটে 0 – 4 পর্যন্ত যে সংখ্যা দেখছি, এগুলোকে বলা হয়, একটা অ্যারের ইনডেক্স। আমি যখন অ্যারে ডিক্লিয়ারের জন্য “ int st[5]; ” লিখেছিলাম, তখন র্যামে ৫ টি ইন্টিজার জমা রাখার জন্য ৫ টি কনজিকিউটিভ ব্লক তৈরী হয়েছিল, যার ০ ইনডেক্স এ বসবে প্রথম ইন্টিজার অর্থাৎ st[0] এবং ৪ ইনডেক্স এ বসবে শেষ ইন্টিজারটি অর্থাৎ st[4] – এভাবে পরপর মোট ৫টি ইন্টিজারের জন্য জায়গা তৈরী হয় কম্পিউটারের র্যাম এ।
এবার আসি অ্যারে ব্যবহারের দ্বিতীয় সুবিধা তে। লুপিং। আমি যদি, আমার ৫ টি স্টুডেন্ট এর পরীক্ষার মার্কস প্রিন্ট করতে চাই, তাহলে আমাকে নিচের লাইনগুলো লিখতে হবে।
printf("%d\n", st[0]);
printf("%d\n", st[1]);
printf("%d\n", st[2]);
printf("%d\n", st[3]);
printf("%d\n", st[4]);
এই সবগুলো লাইনে আমি ঠিক একই কাজ করছি। একই ভাবে ৫ টি ভ্যারিয়েবল প্রিন্ট করছি। ভ্যারিয়েবলের নাম গুলোও একই, শুধু ইনডেক্স আলাদা। ইনডেক্স গুলো ০ থেকে ৪ রেঞ্জে। এই একই কাজ বার বার না করে আমরা একটা ফর(FOR) লুপ ব্যবহার করতে পারি নিচের মত করে।
#include<stdio.h>
int main()
{
int st[5];
st[0] = 56;
st[1] = 62;
st[2] = 33;
st[3] = 25;
st[4] = 84;
printf("Displaying Exam Marks: \n");
int i;
for(i=0; i<5; i++)
{
printf("%d\n", st[i]);
}
return 0;
}
যে ৫টি লাইনের কাজ কমিয়ে ফেলতে চাই লুপ ব্যবহার করে, তাদের মধ্যে একটাই পার্থক্য, তা হল, অ্যারের ইনডেক্স, যা ০ থেকে ৪ পর্যন্ত। তাই লুপ এ i এর মানও ০ থেকে ৪ পর্যন্ত সীমাবদ্ধ থাকবে। প্রথমবার যখন লুপ এ ঢুকবে, তখন i এর মান ০। অর্থাৎ st[0] এর ভ্যালু প্রিন্ট হবে, অর্থাৎ ৫৬, এরপর (এখন i এর মান বেড়ে ১) st[1] অর্থাৎ ৬২, এভাবে চলতে থাকবে যতক্ষণ না অ্যারের শেষে গিয়ে পৌঁছায়।
এখানে আমি মার্কস প্রিন্ট করেছি লুপ দিয়ে। কিন্তু মার্কস এর ইনপুট ইউজার থেকে না নিয়ে, হার্ডকোড করে দিয়েছি। তোমরা চাইলে ইনপুট গুলোও লুপের মাধ্যমে নিতে পারো।
এই প্রোগ্রামের ক্ষেত্রে আমি ফিক্সড করে দিয়েছি যে আমার ক্লাসে ৫ টি ছাত্র, তাই আমি ৫ সাইজের অ্যারে নিয়েছি। কিন্তু এমন যদি হয় যে, এই ছাত্রসংখ্যা ফিক্সড না, যে প্রোগ্রাম টা ইউজ করবে তার উপর নির্ভর করবে অ্যারের সাইজ বা ছাত্রসংখ্যা? এমন একটা উদাহরণ নিচে দিচ্ছি।
#include<stdio.h>
int main()
{
int n;
scanf("%d", &n);
int st[n];
return 0;
}
এখানে আমি প্রোগ্রামের শুরুতে n একটা ভ্যারিয়েবলের ইনপুট নিয়েছি। পরে এই n কেই অ্যারের সাইজ হিসেবে ব্যবহার করেছি। অর্থাৎ ইউজার যদি ইনপুট ৭ দেয় তাহলে ৭ সাইজের একটা অ্যারে তৈরী হবে, ইনপুট ১০ দিয়ে ১০ সাইজের অ্যারে তৈরী হবে। তার মানে অ্যারের সাইজ আগের প্রোগ্রাম এর মত ফিক্সড নাই। তাহলে, এখন, অ্যারের ইনডেক্স হবে ০ থেকে n-১ পর্যন্ত।
অ্যারে ভ্যালু ইনিশিয়ালাইজ করা অর্থাৎ অ্যারের ইনডেক্স এর ভ্যালু গুলো আগে থেকে ঠিক করে দেওয়ার একটা উপায় আগেই দেখানো হয়েছে।
int st[5];
st[0] = 56;
st[1] = 62;
st[2] = 33;
st[3] = 25;
st[4] = 84;
আরেকটা উপায় হল –
int st[] = {56, 62, 33, 25, 84};
দুইটার কাজ একই। দ্বিতীয় উপায়ে একটা জিনিস লক্ষণীয়, তা হল, এখানে আমি অ্যারের সাইজ ডিফাইন করিনি। যেহেতু আমি অ্যারে ডিক্লিয়ারেশনের সময় ই ভ্যালু গুলো দিয়ে দিচ্ছি, তাই অ্যারে নিজে থেকেই বুঝতে পারে যে মোট কতগুলো ভ্যালু বসবে বা সাইজ কত হবে। তাই এক্ষেত্রে সাইজ বলে দিতে হয় নি। অন্য সব ক্ষেত্রে অ্যারে সাইজ ডিফাইন করা লাগবে।
অ্যারে যেকোন কিছুর হতে পারে যেমন, ইন্টিজার, ডাবল, ফ্লোট, স্ট্রাকচার, ক্যারেক্টার। অ্যারে নিয়ে এ পর্যন্তই। নিচের টাস্ক গুলো করলে অ্যারে নিয়ে ধারনা হয়ত আরও পরিষ্কার হবে।
*** ৫ সাইজের একটি অ্যারেতে ইউজারের কাছ থেকে ইনপুট নিয়ে তা প্রিন্ট করা। ইনপুট নেওয়া এবং প্রিন্ট করা দুইটিই ফর লুপ দিয়ে করতে হবে।
*** ১০ সাইজের একটি অ্যারে নিজের ইচ্ছামত ভ্যালু দিয়ে ইনিশিয়ালাইজ করে শুধু মাত্র জোড়(ইভেন) ইনডেক্সগুলোর ভ্যালু প্রিন্ট করতে হবে।
*** একটি অ্যারেতে ক্লাসের ১০ জন ছাত্রের পরীক্ষার মার্কস থাকবে, এরপর ইউজার যেকোন একজন ছাত্রের রোল ইনপুট দিবে এবং তারপর শুধুমাত্র সেই রোলের পরীক্ষার মার্কস প্রিন্ট করে দেখাতে হবে।
int st[5];
st[0] = 56;
st[1] = 62;
st[2] = 33;
st[3] = 25;
st[4] = 84;
যখন আমরা উপরের কোডটি লিখি তখন একটা লিনিয়ার বা ওয়ান ডাইমেনশনাল অ্যারে তৈরী হয়। নিচের ছবিটা দেখলে হয়ত আরও পরিষ্কার হবে।
খুব সোজাভাবে বললে, কোডে যতগুলো থার্ড ব্র্যাকেট পেয়ার থাকবে, অ্যারের ডাইমেনশন তত। ধর, একটা অ্যারের নাম “ara” এবং আমি কোডে লিখলাম “int ara[3][5];” তাহলে একটি Two Dimesional Array বা 2D অ্যারে তৈরী হবে। আবার যদি আমি লিখি, “int ara[3][4][5];” তাহলে একটি 3D অ্যারে তৈরী হবে। যদিও আমরা মূলত 2D অ্যারেই পড়ব এই কোর্সে।
2D অ্যারে মূলত অনেকগুলো 1D বা লিনিয়ার অ্যারের সমষ্টি। আবারে এটাকে একটা 2D ম্যাট্রিক্স এর মত করেও চিন্তা করতে পারি আমরা। কোডে পরে যাব আমরা, নিচে একটি 2D অ্যারের গ্রাফিক্যাল এক্সাম্পল দিচ্ছি।
অর্থাৎ 2D অ্যারে ডিক্লিয়ার করার সময় আমাদের দুইটি জিনিস স্পেসিফাই করে দিতে হবে, প্রথমটি কয়টি Row এবং দ্বিতীয়টি কয়টি Column, এক্ষেত্রে ৩ এবং ৫। ইন্ডেক্সিং জিনিসটা খুব ভালোভাবে বুঝতে হবে। মনে করে দেখ, 1D অ্যারের ক্ষেত্রে যদি কোন অ্যারের ক্ষেত্রে সাইজ হত ৫ তবে, অ্যারের ইনডেক্স হত ০ থেকে ৪ পর্যন্ত। যদি কোন অ্যারে আমরা এভাবে ডিক্লিয়ার করতাম - “int ara[5]” তাহলে, এর প্রথম ইনডেক্স হত ০ এবং প্রথম ইনডেক্স এ যে এলিমেন্ট/ভ্যালু আছে তা হত ara[0], অর্থাৎ আমরা যদি ara[0] প্রিন্ট করতাম, তাহলে অ্যারের প্রথম ইনডেক্স এ যে ভ্যালু আছে সেইটা প্রিন্ট হত। আর শেষ ইনডেক্স হত ৪ এবং আমরা যদি ara[4] প্রিন্ট করতাম তাহলে অ্যারের শেষ ইনডেক্স এ যে ভ্যালু আছে সেটা প্রিন্ট হত। এখানে(1D অ্যারের ক্ষেত্রে) যেকোন এলিমেন্ট এর ইনডেক্স শুধু মাত্র একটি জিনিসের উপর নির্ভর করে, তা হল, লিনিয়ারলি কত নম্বর ঘরে আছে ভ্যালুটা।
কিন্তু, এই ব্যাপারটি একটু আলাদা হয়ে যায় 2D অ্যারে বা ম্যাট্রিক্স এর ক্ষেত্রে। কারণ, এখানে যেকোন একটা ভ্যালু বা এলিমেন্ট এর সঠিক অবস্থান জানতে আমাদের দুইটি ইনফরমেশন প্রয়োজন হয়, প্রথমটি – এলিমেন্টটি কত নম্বর Row তে আছে এবং দ্বিতীয়টি – কত নম্বর Column। তাই, 1D অ্যারেতে ইনডেক্স ছিল শুধু একটা সংখ্যা। কিন্তু 2D অ্যারেতে ইনডেক্স হবে দুইটা সংখ্যা – Row নম্বর এবং Column নম্বর।
2D অ্যারের ক্ষেত্রে ইনডেক্স এর রেঞ্জ – অ্যারে “ara” তে Row আছে ৩টি এবং Column আছে ৫টি। তাই Row এর রেঞ্জ হবে ০ থেকে ২ পর্যন্ত। Column এর রেঞ্জ হবে ০ থেকে ৪ পর্যন্ত। তাই সবচেয়ে উপরের বাম দিকের এলিমেন্টের ইনডেক্স হবে – 0,0(Row No. 0 and Column No. 0) এবং এলিমেন্টটি- ara[0][0]। আর, ডান দিকের সবচেয়ে নিচের এলিমেন্ট এর ইনডেক্স এবং ভ্যালু যথাক্রমে 2,4(Row No. 2 and Column No. 4) এবং ara[2][4]। ইনডেক্স গুলো উপরের ছবিটি দেখলেই বুঝতে পারবে।
আবার উপরের ছবিটি লক্ষ্য করে দেখ, এই 2D অ্যারের প্রতিটি Row কে আমরা একটা করে 1D অ্যারে কল্পনা করতে পারি। সেই হিসেবে ara[0] একটি ৫ সাইজের 1D অ্যারে। যার প্রথম ইনডেক্স ০ এবং শেষ ইনডেক্স ৪। সুতরাং, ara[0] এর এলিমেন্টসমূহ ara[0][0], ara[0][1], ara[0][2], ara[0][3] এবং ara[0][4]। একই ভাবে ara[1] এবং ara[2] ও আলাদা দুইটি ৫ সাইজের 1D অ্যারে। এরপর আমরা দেখব 2D অ্যারে রিলেটেড কিছু কোডিং।
সবকিছুই 1D অ্যারের মতই। প্রথমে ডাটা টাইপ, তারপর অ্যাারের নাম এবং সবশেষে কয়টি Row এবং Column – এটা অ্যারে ডিক্লিয়ারেশন। ভ্যালু ইনিশিয়ালাইজেশন আগের মতই ইনডেক্স ধরে ধরে করতে হবে। আর, ইন্ডিভিজুয়াল এলিমেন্ট এর ভ্যালু প্রিন্ট করার জন্য “printf(“%d”, ara[1][3]);” লেখাই যথেষ্ট। একই ভাবে আমরা “printf” এর জায়গায় “scanf” ব্যবহার করে ইনপুট নিতে পারব, সাথে অ্যাাম্পারস্যান্ড সাইন ইউজ করতে হবে। নিচে কোড দিয়ে দিচ্ছি।
#include<stdio.h>
int main()
{
int ara[3][5];
ara[0][0] = 56;
ara[0][1] = 62;
ara[0][2] = 33;
ara[0][3] = 25;
ara[0][4] = 84;
ara[1][0] = 13;
ara[1][1] = 12;
ara[1][2] = 15;
ara[1][3] = 21;
ara[1][4] = 23;
ara[2][0] = 2;
ara[2][1] = 8;
ara[2][2] = 91;
ara[2][3] = 87;
ara[2][4] = 77;
printf("First element is - %d\n", ara[0][0]);
printf("Element from second row, third column is - %d\n", ara[1][2]);
printf("Last element is - %d\n", ara[2][4]);
return 0;
}
এখানে আমরা অ্যারে ভ্যালু ইনিশিয়ালাইজেশনের জন্য, ভ্যালুগুলো হার্ডকোড করে দিয়েছি। কিন্তু বাস্তবে আমরা বেশীরভাগ সময়ই ভ্যালুগুলো ইউজার থেকে ইনপুট নেই। অর্থাৎ প্রতিটা ইনডেক্স এর জন্য আমাদের আলাদা আলাদা “scanf” লাগবে। ১৫ টা ভ্যালু নেবার জন্য ১৫ বার। যদি সত্যিই আমি ১৫ বার “scanf” লিখি, তাহলে আমার কোড কাজ করবে ঠিকই, কিন্তু এই প্রোসিডিউরটা মোটেই এফিশিয়েন্ট হবে না। যেহেতু একই কাজ আমরা বার বার করছি, তাই আমাদের লুপ ইউজ করতে হবে। আমি “For Loop” ব্যবহার করে দেখাচ্ছি, তোমরা While দিয়েও করে দেখতে পারো। এভাবে চিন্তা কর যে, আমার 2D অ্যারেটা ৩টা 1D অ্যারের সমষ্টি। তাহলে, এই টিনটা 1D অ্যারের ইনপুট আলাদা তিনটা “For Loop” দিয়ে নিয়েই হল। আর 1D অ্যারের ইনপুট নেওয়া তো আমরা আগেই দেখে আসছি। আর, একইভাবে আমরা অ্যারের ভ্যালু গুলো লুপ দিয়ে প্রিন্ট ও করতে পারব। শুধু “scanf” এর জায়গায় “printf” এবং অ্যাাম্পারস্যান্ড উঠে যাবে। নিচের কোডটা লক্ষ্য কর।
#include<stdio.h>
int main()
{
int ara[3][5];
int j;
//Input
for(j=0;j<5;j++)
{
scanf("%d",&ara[0][j]);
}
for(j=0;j<5;j++)
{
scanf("%d",&ara[1][j]);
}
for(j=0;j<5;j++)
{
scanf("%d",&ara[2][j]);
}
//Output
for(j=0;j<5;j++)
{
printf("%d ",ara[0][j]);
}
for(j=0;j<5;j++)
{
printf("%d ",ara[1][j]);
}
for(j=0;j<5;j++)
{
printf("%d ",ara[2][j]);
}
return 0;
}
যেহেতু ৩টি অ্যারে, তাই ইনপুট নিতে ৩টি লুপ লাগছে, আবার, প্রিন্ট করতেও। আমাদের প্রথম 1D অ্যারে টি ছিল ara[0] এবং এর এলিমেন্ট ছিল ৫ টি। তাই প্রথম লুপে আমি ara[0] এর ইনপুট নিয়েছি। ৫ টি এলিমেন্ট এর জন্য “j” এর মান ০ থেকে ৪ পর্যন্ত নিয়েছি। এরপরের অ্যারেগুলো (ara[1], ara[2]) এবং আউটপুটের ক্ষেত্রেও তাই। এবার, একটা মজার জিনিস হল, ইনপুটের ৩টা “For Loop” ই একই কাজ করছে। একটাই পার্থক্য, ara – 0, 1, 2. এই তিনটা জিনিস পরিবর্তন করার জন্য ৩টা আলাদা লুপ ব্যবহার না করে, আমরা একটা নেস্টেড লুপ ব্যবহার করতে পারি নিচের মত করে যার কাজ হবে ৩ বার চলা, এবং মান হবে ০, ১ এবং ২।
#include<stdio.h>
int main()
{
int ara[3][5];
int i,j;
//Input
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
{
scanf("%d",&ara[i][j]);
}
}
//Output
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
{
printf("%d ",ara[i][j]);
}
}
return 0;
}
এই হিসেব টা বেশ সহজ। “ara[5]” এ মোট এলিমেন্ট কয়টা? – ৫ টা। “ara[3][5]” এ কয়টা? – ১৫ টা। এই ১৫ সংখ্যাটা কিভাবে আসলো? ৩ টি ৫ সাইজের অ্যারে, তাই ৩*৫ = ১৫। আবার “ara[4][2][3]” এর এলিমেন্ট সংখ্যা ৪*২*৩ = ২৪ টা।
2D অ্যারে কতটা ভালো বুঝেছ, এটার জন্য নিচের টাস্কগুলো করে দেখতে পার।
***একটা স্কুলে ৩ টা ক্লাস আছে, এবং প্রতি ক্লাসে ৫ টা ছাত্র আছে। সবার বাংলা পরীক্ষার মার্কস ইনপুট নিয়ে আউটপুটে দেখাবে, কোন ক্লাসের গড় মার্কস কত।
***উপরের টাস্কে আমি বলে দিয়েছি, ৩ টা ক্লাস এবং ৫ টা ছাত্র। এবার, এই ইনফরমেশন বলা থাকবে না। কয়টি ক্লাস এবং কতজন ছাত্র আছে সেটিও ইউজার ইনপুট দিবে। তারপর আগের মতই আউটপুটে প্রতি ক্লাসের গড় মার্কস দেখাবে।