5.7.11 অ্যারে (Array)

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

data type name [number of elements];

উদাহরণ ১৫

নিচের প্রোগ্রামটিতে একটি অ্যারে তৈরি করা হবে, যেখানে পাঁচজন শিক্ষার্থীর একটি পরীক্ষায় প্রাপ্ত নম্বর রাখা হবে।

#include <stdio.h>

int main()
{
	int marks [5];

	// assign marks to array
	marks[0] = 87;
	marks[1] = 82;
	marks[2] = 76;
	marks[3] = 85;
	marks[4] = 88;

	/* now print the marks */
	printf ("%d\n", marks [0]);
	printf ("%d\n", marks [1]);
	printf ("%d\n", marks [2]);
	printf ("%d\n", marks [3]);
	printf ("%d\n", marks [4]);
	return 0;
}

প্রোগ্রামঃ 5.21

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

উপরের প্রোগ্রামটিতে marks নামের যেই অ্যারেটি তৈরি করা হয়েছে (int marks[5;]), সেখানে বলে দেওয়া হয়েছে যে, অ্যারেটি ইন্টিজার টাইপের অর্থাৎ অ্যারের সব উপাদান হবে ইন্টিজার আর অ্যারেতে মোট 5টি উপাদান থাকবে। অ্যারের প্রথম উপাদান থাকে 0-তম ঘরে, দ্বিতীয় উপাদান থাকে 1-তম ঘরে, তৃতীয় উপাদান থাকে 2-তম ঘরে, এরকমভাবে n-তম উপাদান থাকে (n – 1)-তম ঘরে। এই ঘরগুলোকে বলা হয় অ্যারের ইনডেক্স (index)। মনে রাখতে হবে যে, সি প্রোগ্রামিং ভাষায় অ্যারের ইনডেক্স 0 থেকে শুরু হয়, 1 থেকে নয়। তাহলে marks অ্যারেটিতে বিভিন্ন মান থাকবে নিচের চিত্রের মতো,

Value8782768588
Index01234

ইনডেক্স থাকার একটি সুবিধা হচ্ছে যে, এখানে লুপ ব্যবহার করা যায়। যেমন- পাঁচবার Printf() স্টেটমেন্ট না লিখে এভাবেও লেখা যেত-

for (i = 0; i < 5; i = i + 1)
{
	printf ("%d\n", marks [i]);
}

আবার অ্যারেতে বিভিন্ন মান অ্যাসাইন করার কাজটি সংক্ষেপে করা যায় এভাবে-

Int marks[] = {87, 82, 76, 85, 88};

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

for (i = 0; i < 5; i = i + 1)
{
	scanf ("%d", &marks [i]);
}

মনে রাখতে হবে, অ্যারের ইনডেক্স সব সময় হবে একটি পূর্ণসংখ্যা, যেটি 0 থেকে শুরু হবে। আর অ্যারেতে n সংখ্যক উপাদান থাকলে অ্যারের ইনডেক্স-এর সর্বোচ্চ মান হবে n-1।

উদাহরণ ১৬

একটি অ্যারেতে দশটি সংখ্যা রাখা আছে। সংখ্যাগুলোর যোগফল বের করতে হবে-

#include <stdio.h>

int main()
{
	int numbers [10] = {9, 76, 2, 45, 3, 81, 25, 33, 71, 10};
	int i, sum;
	sum = 0;
	for (i = 0; i < 10; i = i + 1) {
		sum = sum + numbers [i];
	}
	printf ("Sum: %d\n", sum);
	return 0;
}

একটি ফাংশনে যখন কোনো ভ্যারিয়েবল ডিক্লেয়ার করা হয় (যেমন int sum), তখন সেই ভ্যারিয়েবলের ভেতরে কোনো মান দেওয়া থাকে না। সেই ভ্যারিয়েবলটির ভেতরে যে কোনো মান থাকতে পারে, যাকে গারবেজ (garbage) মান বলা হয়। তাই ভ্যারিয়েবলটির ভেতর যদি 0 রাখার প্রয়োজন হয়, তখন এর মধ্যে 0 অ্যাসাইন করতে হবে (যেমন- sum = 0)। আর যোগফল নির্ণয়ের প্রোগ্রামটিতে এমনটি করতে হয়েছে কারণ sum = sum + numbers[i] স্টেটমেন্ট চলার আগে ‍sum-এর মান 0 করে দেওয়ার ফলে 0+9 অর্থাৎ 9 সংখ্যাটি sum-এর মধ্যে আবার রাখা যাচ্ছে।

a = a + b; এই স্টেটমেন্টটি সি ভাষায় আরেকভাবে লেখা যায় : a +=b; তাহলে প্রোগ্রাম এ for লুপ এভাবে লেখা যায়,

for (i = 0; i < 10; i += 1)
{
	sum += numbers [i];
}

আবার i += 1 (বা, i = i + 1)-কে i++ লেখা যায়। এটি একটি সংক্ষিপ্ত রূপ। যে কোনো একভাবে লিখলেই চলে।

উদাহরণ ১৭

একটি অ্যারেতে পাঁচটি সংখ্যা আছে। একটি প্রোগ্রাম লিখে সংখ্যাগুলোর ক্রম উল্টে দিতে হবে। অর্থাৎ অ্যারেতে যদি 1, 2, 3, 4, 5 থাকে, তাহলে প্রোগ্রামটি অ্যারেতে 5, 4, 3, 2, 1 ‍নিয়ে আসবে।

প্রোগ্রামটি লেখার আগে একটি অপেক্ষাকৃত সহজ প্রোগ্রাম করে দেখতে হবে। ধরা যাক, দুটি ভ্যারিয়েবল আছে, a ও b। এখন একটি প্রোগ্রাম লিখতে হবে যেন, a-এর মান b-তে চলে আসে আর b-এর মান a-তে চলে আসে। কাজটি করার উপায় কী? একটি সহজ উপায় হচ্ছে, অতিরিক্ত একটি ভ্যারিয়েবল c ব্যবহার করা। তারপরে c-এর ভেতরে a-এর মান অ্যাসাইন করা। তাহলে এখন c ও a-তে একই মান থাকবে। এখন b-এর মান a-তে অ্যাসাইন করা হবে। তাহলে c-তে থাকবে a-এর আসল মান, a ও b-তে থাকবে b-এর মান। তারমানে b-এর মান কিন্তু a-তে চলে এলো। এখন, a-এর আসল মান b-তে আনতে পারলেই কাজ শেষ। c-এর মধ্যে a-এর আসল মান আছে। তাই b = c; লিখলেই কাজ হয়ে যাবে। বিষয়টি অনেকটা নিচের ছবির মত।

#include <stdio.h>

int main()
{
	int a = 15, b = 9;
	int c;
	c = a;
	a = b;
	b = c;
	printf ("Value of a is %d, value of b is %d\n", a, b);
	return 0;
}

এখন আসল সমস্যাটির সমাধান করা হবে। অ্যারের প্রথম উপাদনের সঙ্গে অ্যারের শেষ উপাদানের আগের উপাদানের মানের অদলবদল করা হবে।

প্রোগ্রামটি লেখা যায় এভাবে-

#include <stdio.h>

int main()
{
	int ara[] = {10, 20, 30, 40, 50};
	int n = 5, i;
	int temp;

	for (i = 0; i < n / 2; i += 1)
	{
		// To exchange the value of ara [i] and ara [n-l-i]
		temp = ara[i];
		ara[i] = ara[n-1-i];
		ara[n-1-i] = temp;
	}
	for (i = 0; i < n; i += 1)
	{
		printf ("%d\n", ara[i]);
	}
	return 0;
}

সি প্রোগ্রামিং ভাষায় ক্যারেক্টার টাইপের ভ্যারিয়েবলে একটি অক্ষর রাখা যায়। যদি একাধিক অক্ষর রাখতে হয়, তখন ক্যারেক্টার টাইপের অ্যারে ব্যবহার করা হয়। একে বলা হয় স্ট্রিং (string)। বিভিন্ন প্রোগ্রামিং ভাষায় স্ট্রিংয়ের জন্য পৃথক ডেটা টাইপ থাকলেও সি-তে আলাদা কোনো ডেটা টাইপ নেই।

উদাহরণ ১৮

নিচের প্রোগ্রামের মাধ্যমে দেখানো হবে সি-তে কীভাবে স্ট্রিং ইনপুট নেওয়া যায় ও আউটপুট দেওয়া যায়,

#include <stdio.h>

int main()
{
	char name[80];
	scanf ("%s", &name);
	printf ("%s\n", name);
	return 0;
}

যেই স্ট্রিং ইনপুট দেওয়া হবে, প্রোগ্রামটির সেই স্ট্রিং আউটপুট হিসেবে প্রিন্ট করবে। একটি স্ট্রিংয়ের শেষ অক্ষরটি হবে নাল ক্যারেক্টার (‘\0’)। তাই কোনো স্ট্রিংযে যদি বলে দেওয়া হয় সর্বোচ্চ 80টি ঘর থাকবে (name[80]), তাহলে এখানে আসলে সর্বোচ্চ 79টি অক্ষর রাখা যাবে। শেষ ঘরটি নাল ক্যারেক্টারের জন্য বরাদ্দ রাখতে হবে।

সাধারণ ইন্টিজার অ্যারেতে ইনপুট নিতে হলে যেমন একটি লুপ ব্যবহার করে একটি একটি করে সংখ্যা ইনপুট নিতে হয়, ক্যারেক্টার অ্যারে বা স্ট্রিংয়ের ক্ষেত্রে তার প্রয়োজন হয় না। scanf() ফাংশনের ভেতরে %s ব্যবহার করে সম্পূর্ণ স্ট্রিংটি একসাথে ইনপুট নেওয়া যায়। তবে স্ট্রিংয়ের ভেতরে কোনো স্পেস (space) ক্যারেক্টার থাকতে পারবে না।

নিচের ছবিতে একটি স্ট্রিং “Bangla” কীভাবে অ্যারেতে থাকে, সেটি দেখানো হয়েছে-

Value‘B’‘a’‘n’‘g’‘I’‘a’‘\0’
Index0123456

উদাহরণ ১৯

এখন একটি প্রোগ্রাম লেখা হবে, যেটি একটি স্ট্রিংয়ে কতগুলো অক্ষর বা ক্যারেক্টর আছে, সেটি বের করবে-

#include <stdio.h>

int main()
{
	char name[80];
	int i, length;
	scanf ("%s", name);
	i = 0;
	while (name[i] != '\0')
	{
		i = i + 1;
	}
	length = i;
	printf ("%s has %d characters.\n", name, length);
	return 0;
}

এখানে i-তে 0 অ্যাসাইন করা হয়েছে। তারপর while লুপের ভেতরে শর্ত পরীক্ষা করা হচ্ছে যে, name[i]-এর মান নাল ক্যারেক্টার কি না। যদি না হয়, তাহলে লুপের ভেতরে i-এর মান এক বাড়ানো হয়েছে। যখন name[i]-এর মান নাল ক্যারেক্টারের সমান হবে, তখন প্রোগ্রামটি লুপ থেকে বের হয়ে যাবে। আর i-এর মানই হবে স্ট্রিংয়ের দৈর্ঘ্য, যেটি length নামক ভ্যারিয়েবলে অ্যাসাইন করা হয়েছে। উল্লেখ যে, একটি স্ট্রিংয়ে মোট অক্ষরের সংখ্যাকে সেই স্ট্রিংয়ের দৈর্ঘ্য বলা হয়।

উদাহরণ ২০

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

#include <stdio.h>

int main()
{
	int ara[] = {1, 2, 3, 5, 8, 13, 21, 34, 55};
	int key, i, n;

	n = 9;

	scanf ("%d", &key);
	for (i = 0; i < n; i += 1)
	{
		if (ara[i] == key)
		{
			printf ("%d is found in the array.\n", key);
			break;
		}
	}
	if (i == n)
	{
		printf("%d is not found in the array.\n", key);
	}
	return 0;
}

উপরের প্রোগ্রামে break স্টেটমেন্ট ব্যবহার করা হয়েছে। এই স্টেটমেন্ট এক্সিকিউট হলে লুপের ভেতর থেকে প্রোগ্রামটি বের হয়ে যাবে। key যদি অ্যারেতে পাওয়া যায়, তাহলে আর খোঁজার কোনো প্রয়োজন নেই, তাই লুপ থেকে বের হয়ে যেতে হবে। লুপ থেকে বের হওয়ার তাহলে দুটি উপায়, এক হচ্ছে break; এক্সিকিউট হওয়া, আর নইলে সব সংখ্যা পরীক্ষা করা হয়ে গেলে i-এর মান n-এর সমান হয়ে যাবে, তখন I < n শর্তটি মিথ্যা হয়ে যাবে আর প্রোগ্রামটি লুপ থেকে বের হয়ে যাবে। তাই for লুপের ব্লকের বাইরে পরীক্ষা করা হচ্ছে যে, I আর n-এর মান সমান কি না। যদি সমান হয়, তাহলে বুঝতে হবে break স্টেটমেন্ট এক্সিকিউট হয়নি, অর্থাৎ সংখ্যাটি খুঁজে পাওয়া যায়নি। এই পদ্ধতিতে বলা হয় লিনিয়ার সার্চ (linear search)।