.১ - ফাংশন কি?
ফাংশন হচ্ছে যে কোন প্রসিডিউরাল প্রোগ্রামিং ল্যাংগুয়েজ এর বিল্ডিং ব্লক বা গঠনগত একক। 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 ; ব্যবহার করা ঠিক না।
- ফাংশনের রিটার্ন ভ্যালু গ্রহনের জন্য কলিং ফাংশন এ সঠিক ডেটা টাইপের ভ্যারিয়েবল থাকতে হবে। এই ক্ষেত্রে এসাইনমেন্ট অপারেটর ব্যবহার করে ভ্যারিয়েবলে রিটার্ন ভ্যালু এসাইন করা যাবে। এমন কোন এক্সপ্রেশন যদি থাকে যেখানে রিটার্ন টাইপের ডেটা সরাসরি ব্যবহার করা সম্ভব, সেখানে ফাংশনটিকে সরাসরিও ব্যবহার করা যাবে। তবে সেটা না করাই ভালো।
- কলিং ফাংশন যদি ফাংশনের রিটার্ন ভ্যালু গ্রহণ না করে তাহলে কোন ক্ষতি নেই। ভ্যালুটি স্রেফ হারিয়ে যাবে। কাজেই রিটার্ন ভ্যালু আছে এমন কোন ফাংশন কল করলেই যে তার রিটার্ন ভ্যালু আমাদের কাজে লাগাতে হবে এমন কোন কথা নেই। যদি আমাদের সেটা কাজে লাগে, তাহলে আমরা ব্যবহার করবো, আর না লাগলে সেটা উপেক্ষা করবো।
.৬ - প্যারামিটার যুক্ত ফাংশন : আর্গুমেন্ট সহ ফাংশন কল করা