C কন্ডিশনাল স্টেটমেন্ট : লুপ

C এর খুব মজার একটা জিনিস হল এর syntax বেশ সহজ, কিন্তু খুব মাথা না খাটিয়ে এটা দিয়ে তেমন কিছুই করা যায় না।

তবুও শুধু C এর syntax গুলা শিখতে পারলেও অনেক লাভ। কারন, বিভিন্ন স্টেটমেন্ট যেমনঃif, switch, for, while ইত্যাদি C++/java তে প্রায় একই রকম।

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

C এর তিনটা লুপ স্টেটমেন্ট আছে। for, while এবং do while। প্রায় সব কাজই এই তিনটার যে কোন একটা দিয়ে করা যায়। তারপরেও অবস্থা বুঝে একেকটার একেক রকম সুবিধা ও অসুবিধা থাকে।

লুপ এক ধরনের কন্ডিশনাল স্টেটমেন্ট। এর মানে হচ্ছে কোন নির্দিষ্ট শর্তের অধীনে কাজ গুলো বার বার সম্পন্ন হবে। এইটা এমনও হতে পারে যে ১) একটি নির্দিষ্ট সংখ্যক বার কাজটি রিপিট হবে অথবা ২) একটি নির্দিষ্ট শর্ত পুরন না হওয়া পর্যন্ত কাজটি চলতে থাকবে। যেমনঃ ধরা যাক, Sagar Sarker ঠিক করলো যে সে পরপর ৭ দিন বিকাল পাচটায় তার প্রেমিকার সাথে দেখা করতে যাবে এবং তার প্রেমিকার সব চাওয়া পূরন করবে এবং বাসায় চলে আসবে।

তার মানে সে কয়দিন ডেটিং এ যাবে সেটা নির্দিষ্ট, কখন যাবে সেটাও নির্দিষ্ট, প্রেমিকার ইচ্ছা পূরন করবে সেটা নির্দিষ্ট, বাসায় চলে আসবে সেটাও নির্দিষ্ট।

কাজেই আমরা ঘটনাটিকে এই ভাবে লিখতে পারি,

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

for লুপের syntax হচ্ছেঃ

for ( লুপ শুরু করার শর্ত; লুপ চলার শর্ত; শর্তের পরিবর্তন)
{
যে কাজ গুলো বার বার হতে হবে সেই কাজ;
}

সাগরের ঘটনাটা যদি for লুপ দিয়ে লিখতে চাই তাহলেঃ

for (প্রথম দিন; অষ্টম দিনের আগ পর্যন্ত; পরের দিন)
{
if ( বেলা ৫ টা)
{
ডেট শুরু;

ইচ্ছা পূরন;
}
বাসায় ফেরত;
}

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

অর্থাৎ for লুপ কাজ করে এইভাবে:

লুপ শুরুর শর্ত যদি লুপ চলার শর্তের মধ্যে থাকে তাহলে লুপের ভেতরে ঢুকবে, কাজ করবে এবং লুপ চলার শর্তকে হালনাগাদ করবে। হালনাগাদকৃত শর্ত যদি লুপ চলার শর্তের মধ্যে থাকে তাহলে আবার লুপে ঢুকবে, আর না হলে লুপ বন্ধ হয়ে যাবে।

সাধারনভাবে for লুপে শর্ত হিসেবে কাউন্টার ব্যবহার করা হয়। তারমানে লুপ শুরুর শর্ত হিসেবে কাউন্টারের একটা প্রাথমিক মান থাকে। লুপ চলার শর্ত হিসেবে দেওয়া থাকে যে কাউন্টারের মান কততে পৌছানোর আগ পর্যন্ত লুপ চলবে। আর প্রত্যেকবার সফল ভাবে লুপ সম্পন্ন হবার পরে কাউন্টারের মান পরিবর্তিত হবে।

অর্থাৎ

for (day= 1; day<=7; day++)
{
if (time== 1700)
{
date;
}
come home;
}

পরবর্তীতে অন্যান্য লুপ নিয়ে আলোচনা করা হবে।

C এর উপাদান সমূহঃ ভ্যারিয়েবল

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

ভ্যারিয়েবল প্রায় আক্ষরিক অর্থেই বাটির মত। বাটিতে যেমন কিছু রাখা যায়, ঠিক তেমনি ভ্যারিয়েবল এও কোন না কোন ডেটা রাখা যায়।

"ডেটা জমা রাখা এবং প্রয়োজনের সময় সেই ডেটা ব্যবহারের জন্য সরবরাহ করাই ভ্যারিয়েবল এর কাজ"।

ভ্যারিয়েবল এর কিছু বৈশিষ্ট্য নিম্নরূপঃ

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

* ভ্যারিয়েবল এর একটা ডেটা টাইপ থাকতে হয়। কমন সেন্স ব্যবহার করলেই এইটা বোঝা যায়। চুলায় পানি গরম করার জন্য যেমন প্লাস্টিকের বাটি ব্যবহার যায় না, ঠিক তেমনি এক ডেটা টাইপের ভ্যারিয়েবলে অন্য ডেটা টাইপ নিয়ে কাজ করা যায় না। যে ডেটা টাইপের ডেটা নিয়ে কাজ করতে হবে, সেই ডেটা টাইপের ভ্যারিয়েবল ডিক্লেয়ার করতে হবে।

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

* যে ব্লকে কোন ভ্যারিয়েবল কে ডিক্লেয়ার করা হয় সেই ব্লক ও তার অধীনস্থ ব্লক গুলোকে ঐ ভ্যারিয়েবল এর স্কোপ বলা হয়। স্কোপের বাইরে ভ্যারিয়েবল কাজ করতে পারে না। যদি কখনো কোন প্রোগ্রামের কোড এক্সেকিউশনের সময় কোন ভ্যারিয়েবল স্কোপের বাইরে চলে যায় তাহলে সেই ভ্যারিয়েবল তাতে জমা রাখা ডেটা হারিয়ে ফেলে।

* কম্পিউটার এর মেমরিতে প্রত্যেকটি বাইট (byte) এর একটি ঠিকানা থাকে, যাকে মেমরি এড্রেস বলে। যেহেতু ডিক্লেয়ারেশন এর পরে ভ্যারিয়েবল এর জন্য মেমরিতে জায়গা নির্ধারণ করা হয় তাই সেই জায়গারও একটি ঠিকানা বা মেমরি এড্রেস থাকবে। কোন ভ্যারিয়েবল এর জন্য নির্ধারিত স্থান এর ঠিকানাকে সেই ভ্যারিয়েবল এর মেমরি এড্রেস বলে। ভ্যারিয়েবল এর নামে আগে '&' চিহ্নটি ব্যবহার করে ভ্যারিয়েবল এর মেমরি এড্রেস বুঝানো হয়। যেমন: ধরা যাক number একটি ইন্টিজার টাইপের ভ্যারিয়েবল। কাজেই কম্পিউটার মেমরিতে এই ভ্যারিয়েবল এর ঠিকানা হবে &number।

* ভ্যারিয়েবল এর ধরন নির্ধারণ করা একটু কঠিন। কারন এর সর্বজন স্বীকৃত কোন প্রকারভেদ নাই। তবে শেখার সুবিধার জন্য নিচের শ্রেণীবিভাগ মনে রাখা যেতে পারে:

১. একক সাধারণ ভ্যারিয়েবলঃ মৌলিক ডেটা টাইপ দিয়ে ডিক্লেয়ার করা একক ভ্যারিয়েবল সমূহ।

২. সাধারণ ভ্যারিয়েবল এর সমাবেশঃ মৌলিক ডেটা টাইপ দিয়ে ডিক্লেয়ার করা array

৩. বিশেষ একক ভ্যারিয়েবলঃ পয়েন্টার ভ্যারিয়েবল

৪. বিশেষ ভ্যারিয়েবল এর সমাবেশঃ পয়েন্টার array, স্ট্রাকচার ভ্যারিয়েবল, ইউনিয়ন

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

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

যেহেতু ভ্যারিয়েবল একটি নাম, সেহেতু এর নাম করনের কিছু নিয়ম কানুন আছে। কিছু নিয়ম পালন করা বাধ্যতামূলক, কিছু নিয়ম হচ্ছে নামটিকে অধিক গ্রহণযোগ্য করে তোলার জন্য। ☺☺☺

প্রথমেই বাধ্যতামূলক নিয়মগুলো জেনে নিই।

১। ভ্যারিয়েবল এর নাম রাখার জন্য আলফা-নিউমেরিক ক্যারেকটার সমূহ ও স্পেশাল ক্যারেক্টার এর মধ্যে শুধুমাত্র আন্ডার স্কোর '_' ব্যবহার করা যাবে। অর্থাৎ নামে লেটার, নাম্বার ও আন্ডার স্কোর ছাড়া অন্য কিছু ব্যবহার করা যাবে না।

২। শুধু লেটার দিয়ে নামকরন করা গেলেও, শুধু নাম্বার দিয়ে ভ্যারিয়েবল এর নাম রাখা যাবে না। লেটার ও নাম্বার মিলিয়ে নাম রাখা যাবে, তবে সেই ক্ষেত্রে নামটি নাম্বার দিয়ে শুরু হতে পারবে না। যেমন,

asdf রাখা যাবে, কিন্তু 1234 রাখা যাবে না; আবার as12 রাখা যাবে কিন্তু 12as রাখা যাবে না।

৩। আন্ডার স্কোর দিয়ে নাম শুরু করা যাবে। যেমন,

_asdf রাখা যাবে, _12as রাখা যাবে;

৪। ভ্যারিয়েবল এর নাম করনে কোন প্রকার স্পেস ব্যবহার করা যাবে না। যেমন,

student info নামটি ভ্যালিড নাম নয়। বোধগম্য করা জন্য যদি কোন সেপারেটর ব্যবহার করতে হয় তাহলে আন্ডার স্কোর ব্যবহার করা যাবে। যেমন,

student_info একটি ভ্যালিড ভ্যারিয়েবল এর নাম।

৫। নামের দৈর্ঘ্য সর্বোচ্চ কত হতে পারবে তা কম্পাইলার এর উপর নির্ভর করবে। তবে স্ট্যান্ডার্ড অনুযায়ী কম্পাইলারের ৩১ অক্ষর পর্যন্ত কমপক্ষে সাপোর্ট করার কথা।

এইবার আসি নামকে অধিক ব্যবহার উপযোগী করে তোলার কিছু নিয়ম। এগুলো বাধ্যতামূলক নয়।

৬। নাম যথাসম্ভব সংক্ষিপ্ত হলে ভাল হয়। এতে ভ্যারিয়েবলকে বার বার লিখা সহজ হয়।

৭। নামকে প্রাসঙ্গিক করলে কোডে তার প্রয়োগ বোঝা সহজ হয়।

৮। যদিও নাম সম্পূর্ণ ছোট হাতের অক্ষর, সম্পূর্ণ বড় হাতের অক্ষর বা মিশ্র হতে পারে, তবুও সম্পূর্ণ বড় হাতের অক্ষরে না রাখাই ভাল। প্রচলিত প্রথা অনুযায়ী সম্পূর্ণ বড় হাতের অক্ষরে নাম রাখা হয় প্রিপ্রসেসর ডিরেক্টিভ #define দিয়ে ডিফাইন করা জিনিসের। তবে, রাখলে কোন ভুল হবে না।


বিশেষ বিশেষ ভ্যারিয়েবল এর ক্ষেত্রে আরো কিছু নিয়ম কানুন আছে। যেমনঃ

→ array ভ্যারিয়েবল এর নাম এর সাথে [ ] থাকে। এই ব্র‍্যাকেট এর মধ্যে array এর ইন্ডেক্স সংখ্যা থাকে। কাজেই একটি array যার নাম number এবং যার ইন্ডেক্স সংখ্যা ১০, তার পুরো নামটি হয় number[10]। আবার এই array তেই যদি ৫ নম্বর ইন্ডেক্সটিকে আমরা চিহ্নিত করতে চাই তাহলে তার নাম হবে number[5]। এইক্ষেত্রে মনে হতে পারে যে ভ্যারিয়েবল এর নাম করনের সময় [ ] কেও নামে রাখা হয়েছে। কিন্তু আসলে ব্যাপারটা সে রকম নয়।

→ pointer এর নাম রাখার সময় নামের আগে * যোগ করা হয়। যেমন, পয়েন্টার p এর নাম লিখার সময় লিখা হয় *p। এখানে তার নাম p এবং * দ্বারা বোঝানো হয় যে এটি একটি পয়েন্টার।

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

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

ভ্যারিয়েবল এর নাম করনের সাথে সাথেই তার ডেটা টাইপও উল্লেখ করতে হয়।

অনেকটা চাইনিজ বা জাপানিজ দের নাম রাখার মত। জানেন তো যে তাদের নামের প্রথম অংশটা তাদের বংশের নাম?

আজকে আমরা যেটা জানবো সেটা হচ্ছে ভ্যারিয়েবল ডিক্লেয়ারেশন, ইনিশিয়ালাইজেশন ও ডেফিনিশন।

ভ্যারিয়েবল ডিক্লেয়ারেশন হচ্ছে একটি ঘোষনার মাধ্যমে জানিয়ে দেওয়া যে, অমুক ডেটা টাইপের অমুক নামের একটি ভ্যারিয়েবল তৈরী করা হল। ডিক্লেয়ার করার নিয়ম হচ্ছে,

data_type variable_name;

তারমানে হচ্ছে যদি আমরা number নামের একটি ইন্টিজার টাইপের ভ্যারিয়েবল ডিক্লেয়ার করতে চাই, তাহলে আমাদের ডিক্লেয়ারেশন স্টেটমেন্ট হবে,

int number;

সহজ, তাই না?

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

float first_gpa, final_gpa, cgpa;

এই স্টেটমেন্ট দ্বারা একই সাথে তিনটি ফ্লোটিং পয়েন্ট টাইপের ভ্যারিয়েবল ডিক্লেয়ার করা হয়ে গেলো।

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

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

ভ্যারিয়েবলকে ডিক্লেয়ার করার পরে তাতে একটি প্রাথমিক ডেটা জমা রাখা হয় যেটা প্রোগ্রামারের জানা থাকে। এই কাজটিকেই বলা হয় ইনিশিয়ালাইজেশন।

যেমনঃ number নামের একটি ইন্টিজার ভ্যারিয়েবলকে ডিক্লেয়ার করে তাতে প্রাথমিক ভাবে 0 জমা রাখার জন্য স্টেটমেন্ট গুলো হবেঃ

int number; //ডিক্লেয়ারেশন স্টেটমেন্ট
number = 0; // ইনিশিয়ালাইজেশন

'=' কে বলা হয় এসাইনমেন্ট অপারেটর যা সম্পর্কে পরবর্তিতে আলোচনা করা হবে। এখন এইটুকুই জেনে রাখা ভাল যে,

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

ইনিশিয়ালাইজ কেন করা হয় তা যখন দরকার পড়বে তখনই বুঝতে পারবে। তবে এখন এইটুকুই জেনে রাখা দরকার যে,

ডিক্লেয়ারেশন এর পর পরই ভ্যারিয়েবল কে ইনিশিয়ালাইজ করার অভ্যাস থাকা ভাল।

আমরা চাইলে একই সাথে ডিক্লেয়ারেশন ও ইনিশিয়ালাইজেশন করতে পারি। এবং বাস্তবে সেটাই করা হয় সাধারণত। সেটা করা হয় এই ভাবে।

int number;
number=0;

এর পরিবর্তে একবারে লেখা হয়,

int number=0;

এই স্টেটমেন্ট এ প্রথমে number নামে একটি ভ্যারিয়েবল ডিক্লেয়ার হয়েছে, তারপর তাতে 0 জমা রাখা হয়েছে।

একই সাথে ডিক্লেয়ারেশন আর ইনিশিয়ালাইজেশন করাকেই ডেফিনিশন বলা হয়ে থাকে।

C এর উপাদান সমূহঃ ক্যারেকটার সেট ও ডেটা টাইপ

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

C ভাষায় প্রোগ্রাম লিখতে হলে a থেকে z পর্যন্ত অক্ষর, 0 থেকে 9 পর্যন্ত অংক আর সচরাচর ব্যবহৃত যতিচিহ্ন সমূহকে ব্যবহার করা যায়। তবে অক্ষরের চেয়ে ব্যাকরণই বিভিন্ন ভাষার মধ্যে পার্থক্য তৈরী করে। কাজেই ইংরেজিতে ব্যবহৃত অক্ষর ও সংখ্যা C ভাষায় ব্যবহৃত হলেও তাদের প্রয়োগ আলাদা এবং C ভাষার নিজস্ব।

C তে প্রোগ্রামিং করার জন্য ৩ ধরনের ক্যারেকটার ব্যবহার করা যায়। ১) আলফা-নিউমেরিক ২) স্পেশাল ক্যারেক্টার বা যতিচিহ্নাদি ও ৩) ফাকা স্থান। আলফা-নিউমেরিক ক্যারেকটার আবার দুই ধরনের। a) alphabet বা বর্ণমালা ও b) ডিজিট বা অংক। তাহলে আমরা C ভাষায় ব্যবহারের জন্য ৪ ধরনের ক্যারেকটার পেলাম।

¢ Alphabet: a-z ও A-Z পর্যন্ত
¢ Digits: 0-9 পর্যন্ত
¢ Special Characters : .,! " ' : ;? % & () {} []= ইত্যাদি
¢ white space: space, TAB, new line (\n) ইত্যাদি

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

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

কাজেই দেখতে পাচ্ছি যে C প্রোগ্রামিং এর অর্থই হচ্ছে ডেটা নিয়ে কাজ করা। C প্রোগ্রামে ডেটাকে তিন উপায়ে শ্রেণীবদ্ধ করা হয়।

১। মৌলিক বা Fundamental শ্রেণীকরণঃ এই শ্রেনীতে 5 ধরনের ডেটা আছে। এই ধরনগুলোকে মৌলিক ডেটা টাইপ বলে। এরা হচ্ছেঃ

** ক্যারেকটার ডেটা: একে কিওয়র্ড char দ্বারা নির্দেশ করা হয়। C ভাষার ব্যবহৃত সকল ক্যারেকটারই char শ্রেনীর অন্তর্ভূক্ত।

** ইন্টিজার ডেটাঃ একে কিওয়র্ড int দ্বারা নির্দেশ করা হয়। শুন্য সহ সকল ধনাত্মক ও ঋণাত্মক পূর্ণসংখ্যা এই শ্রেণীভুক্ত।

** ফ্লোটিং পয়েন্ট ডেটাঃ একে কিওয়র্ড float দ্বারা নির্দেশ করা হয়। ৬ দশমিক স্থান পর্যন্ত সকল ধনাত্মক ও ঋণাত্মক সংখ্যা এই শ্রেনী ভুক্ত।

** ডাবল প্রিসিশান ফ্লোটিং পয়েন্ট ডেটাঃ একে কিওয়র্ড double দ্বারা নির্দেশ করা হয়। ১৪ দশমিক স্থান পর্যন্ত সকল ধনাত্মক ও ঋণাত্মক সংখ্যা সঠিক ভাবে হিসাব করার জন্য এই শ্রেনী।

** ভয়েড (void) ডেটাঃ একে কিওয়র্ড void দ্বারা নির্দেশ করা হয়। যে ধরনের ডেটা উপরের কোন শ্রেনীতেই পড়ে না, তারা এই শ্রেণীভুক্ত। মূলতঃ ফাংশনের রিটার্ন টাইপ ছাড়া এই ডেটা টাইপ ব্যবহৃত হয় না।

২। উদ্ভূত বা লব্ধ বা derived শ্রেণীকরণঃ মৌলিক ডেটা টাইপ গুলো থেকেই এই শ্রেনীর ডেটা টাইপের উৎপত্তি। কাজেই এদের নাম ও কাজ মৌলিক ডেটা টাইপ হতে আলাদা হলেও এরা মূলত তাদেরই পরিবর্তিত রূপ। যেমনঃ

** Array
** String বা NULL terminated Character Array
** Pointer
** Function ইত্যাদি

৩। প্রোগ্রামারের নিজের তৈরী বা user-defined শ্রেণী: এই শ্রেনীতে সেই সব ডেটা টাইপ রয়েছে যাদেরকে প্রোগ্রামার নিজের প্রয়োজনে মৌলিক ও লব্ধ ডেটা টাইপের উপর ভিত্তি করে নিজেই তৈরী করেছেন। কাজেই দেখা যাচ্ছে এরাও আসলে মৌলিক ডেটা টাইপেরই পরিবর্তিত রূপ মাত্র। যেমনঃ

** Structure
** union
** enumerations ইত্যাদি।

Data type যে কোন প্রোগ্রামিং ল্যাংগুয়েজ এর অত্যন্ত গুরুত্বপূর্ণ একটি বিষয়।

ভয়েড ছাড়া বাকি চারটি মৌলিক data type দ্বারাই variable 'declare' করা যায়। Variable ডিক্লেয়ারেশন এর সাথে সাথে কম্পাইলার কম্পিউটার এর মেমোরিতে variable এর জন্য জায়গা নির্ধারণ করে।

Data type এখানেই গুরুত্বটা বহন করে। এক এক ডেটা টাইপের ডেটা মেমরিতে রাখতে এক এক রকম জায়গা লাগে। Data type ই কম্পাইলারকে বলে দেয় যে কোন variable এর জন্য ঠিক কতটুকু জায়গা মেমোরিতে নির্দিষ্ট করে রাখা হবে।

যেমন ১ টি ক্যারেকটার রাখতে যতটুকু জায়গা লাগে, ১ টি ইন্টিজারের জন্য তার থেকে বেশি পরিমান জায়গা লাগে। আবার ফ্লোটিং পয়েন্ট ডেটার জন্য আরো বেশি জায়গা লাগে।

ANSI স্ট্যান্ডার্ড অনুযায়ী যে কোন কম্পাইলারকে
কমপক্ষে
char এর জন্য 8 bit বা 1 byte,
int এর জন্য 16 bit বা 2 byte,
float এর জন্য 32 bit বা 4 byte,
এবং
double এর জন্য 64 bit বা 8 byte

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

যেমন 32-bit ও 64-bit অপারেটিং সিস্টেমে কম্পাইলার int type এর variable এর জন্য 32 bit বা 4 byte জায়গা রাখে।

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

এই জন্য sizeof অপারেটর ব্যবহার করা হয়।

sizeof অপারেটর একটি কম্পাইল টাইম অপারেটর। এটি প্রোগ্রাম কম্পাইল করার সময়ই কাজ করে ঐ এনভায়রনমেন্ট এ কোন ডেটা টাইপের সাইজ কত তা বের করে। যেমন নিচের কোডটি আপনার সিস্টেমে কম্পাইল করে সহজেই আপনি জেনে নিতে পারেন যে আপনার সিস্টেমে কোন ডেটা টাইপের সাইজ কতঃ

#include<stdio.h>

int main()
{

 printf("Size of Different data types in this system:\n\n");
 printf("Data Type\tSize\n\n");
 printf("char\t\t%d-bits/%d byte\n", 8*sizeof(char), sizeof(char));
 printf("int\t\t%d-bits/%d byte\n", 8*sizeof(int), sizeof(int));
 printf("float\t\t%d-bits/%d byte\n", 8*sizeof(float), sizeof(float));
 printf("double\t\t%d-bits/%d byte", 8*sizeof(double), sizeof(double));
 return 0;
}

ফাইল ইনপুট আউটপুট সিস্টেম (File I/O)

FILE I/O (ফাইল ইনপুট / আউটপুট)

আমরা ইতোমধ্যে scanf এবং printf ফাংশন গুলো ডেটা ইনপুট এবং আউটপুট দিতে ব্যবহার করেছি। এরা console oriented I/O ফাংশন, অর্থাৎ এরা টার্মিনাল (কিবোর্ড/স্ক্রীন) এর উপর নির্ভর করে ইনপুট / আউটপুট দিয়ে থাকে। সমস্যা হল-
বড় আকারের ডেটা নিয়ে কাজ করার সময় দুই ধরনের বাধার সম্মুখীন হতে হয়।

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

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

FILE এবং STREAM

C ল্যাংগুয়েজ এ ফাইল বলতে অনেক ধরনের I/O ডিভাইসকে বুঝানো হয়। তবে সবচে বেশি ব্যবহৃত হয় disc file কে বুঝানোর জন্য।

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

প্রোগ্রামার যখন I/O ফাংশন ব্যবহার করেন, তখন স্ট্রীম এর কাজ হল নির্ধারিত ফাইলের সাথে সেই ফাংশনের সম্পর্ক স্থাপন করা এবং ডেটা ব্যবস্থাপনা করা।

একটি open operation এর মাধ্যমে একটি স্ট্রীমের সাথে একটি ফাইলের সম্পর্ক স্থাপন করা হয়।

একটি close operation এর মাধ্যমে একটি স্ট্রীমের সাথে একটি ফাইলের পূর্বে স্থাপিত সম্পর্ক বিচ্ছিন্ন করা হয়।

স্ট্রীম দুই ধরনের।
১. টেক্সট স্ট্রীম
২. বাইনারি স্ট্রীম

টেক্সট স্ট্রীম ASCII ক্যারেক্টার সেট ব্যবহার করে ইনপুট আউটপুট দিয়ে থাকে এবং তা ব্যবহারকারী পড়তে পারে। অর্থাৎ টেক্সট স্ট্রিম ফাইল হতে পড়ার সময় বা ফাইলে লেখার সময় যথাক্রমে human readable থেকে machine readable ভাষায় ইনপুট কে এবং machine readable থেকে human readable ভাষায় আউটপুট কে অনুবাদ করে থাকে। এটা সুবিধাজনক মনে হলেও, তা সবক্ষেত্রে নয়। যেমন, এই অনুবাদের কারনে \n ক্যারেকটার টি 'carriage return+line feed pair' এ রূপান্তরিত হয়। এই পরিবর্তন এর কারনে আসল ডেটা ও ফাইলে লেখা ডেটার মধ্যে এক-এক মিল করন বেশিরভাগ ক্ষেত্রেই সম্ভব হয় না।

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

স্ট্যান্ডার্ড তিনটি স্ট্রীম হল stdin, stdout এবং stderr যারা যথাক্রমে কিবোর্ড, স্ক্রীন এবং স্ক্রীন এর সাথে ইনপুট ও আউটপুট ফাংশনের সম্পর্ক স্থাপন করে থাকে।

সংক্ষেপে-
* ফাইল হল I/O ডিভাইস।
* স্ট্রীম হল I/O ফাংশন ও I/O ডিভাইসের মধ্যে সম্পর্ক স্থাপনকারী।
** পরবর্তী আলোচনায়, ফাইল বলতে আমরা disc file কেই বুঝাবো।

FILE OPERATIONS

ফাইল নিয়ে কাজ করাকে বলে ফাইল অপারেশন। মৌলিক ফাইল অপারেশন এর মধ্যে রয়েছে,

* ফাইল খোলা ( নতুন ফাইল তৈরী, ফাইলের নামকরণ ও অবস্থান নির্ধারণ, কি কাজে ফাইল খোলা হবে তার ডিক্লারেশন ইত্যাদি)

* ফাইল হতে ডেটা read করা

* ফাইলে ডেটা write করা

* ফাইল বন্ধ করা

এছাড়াও কিছু উচ্চতর ফাইল অপারেশন রয়েছে। নিচের ছকে ফাইল অপারেশন এর সংক্ষিপ্ত বর্ণনা দেওয়া হল:

[এই ছকের কিছু না বুঝলে ভয়ের কারন নাই। পরের বিস্তারিত আলোচনায় আশা করি সব পরিস্কার হয়ে যাবে।]

fopen()
* নতুন ফাইল তৈরী
* ফাইলের নামকরণ
* ফাইলের অবস্থান নির্ধারণ
* পূর্বের তৈরী করা আছে এমন কোন ফাইল খোলা
* ফাইল খোলার পরে কি করা হবে তা প্রকাশ করা

fclose()
* ব্যবহারের জন্য খোলা হয়েছিল এমন ফাইল বন্ধ করা

getc()/fgetc()
* ফাইল থেকে একটি করে ক্যারেক্টার read করে

putc()/fputc()
* ফাইলে একটি করে ক্যারেক্টার write করে

getw()
* ফাইল হতে একটি ইন্টিজার read করে

putw()
* ফাইলে একটি ইন্টিজার write করে

fgets()
* ফাইল হতে স্ট্রিং read করে

fputs()
* ফাইলে স্ট্রিং write করে

fread()
* ফাইল হতে বাইনারি ডেটা read করে

fwrite()
* ফাইল এ বাইনারি ডেটা write করে

fprintf()
* ফাইলে এক সেট ডেটা write করে

fscanf()
* ফাইল হতে এক সেট ডেটা read করে

fseek()
* ফাইলের একটি নির্ধারিত অংশে যাওয়ার জন্য ব্যবহৃত হয়

ftell()
* ফাইলের যে অবস্থানে বর্তমানে ফাইল অপারেশন চলছে (current position / current location) সেই অবস্থানকে byte এককে প্রকাশ করে

rewind()
* বর্তমান অবস্থান থেকে ফাইল অপারেশনকে ফাইলের শুরুতে নিয়ে যায়

rename()
* ফাইলের নাম পরিবর্তনের জন্য

remove()
* ফাইল মুছে ফেলার জন্য

feof()
* ফাইল অপারেশন ফাইলের সমাপ্তিতে পৌছেছে কিনা তা চেক করে

ferror()
* কদাচিৎ ব্যবহার করা হয় কোন ফাইল অপারেশনে error হয়েছে কিনা তা পরীক্ষার জন্য।

*** read হচ্ছে ইনপুট অপারেশন ও write হচ্ছে আউটপুট অপারেশন।
*** fseek() এবং ftell() হচ্ছে র‍্যান্ডম একসেস ফাংশন।

(to be continued....)
FILE I/O (ফাইল ইনপুট / আউটপুট) (continued.. Part 1)

FILE খোলা

একটি নতুন ফাইল তৈরী বা আগে থেকে তৈরী একটি ফাইল কোন ফাইল অপারেশন এর জন্য খোলার জন্য fopen() ফাংশন ব্যবহার করা হয়। এর প্রোটোটাইপ

FILE *fopen(char *filename, char *mode)

এবং ব্যবহারের সাধারণ রূপ হচ্ছে

FILE *fp;
fp = fopen("filename.extension", "mode");

ফাইল খোলার জন্য অপারেটিং সিস্টেমকে আমাদের নিম্নোক্ত তথ্যগুলো জানাতে হয়:

১. ফাইলের নাম (file name)
২. ফাইলের ডেটা স্ট্রাকচার (Data Structure)
৩. ফাইল খোলার কারন (purpose)

ফাইলের নাম হল একটি ক্যারেক্টার স্ট্রিং যাতে ফাইলের নাম থাকে এবং নামের সাথে '.' দ্বারা ফাইল নেম এক্সটেনশন যুক্ত থাকে। ফাইল নেম এক্সটেনশন বাধ্যতামূলক নয়, এটি অপশনাল। তবে ফাইল নেম এক্সটেনশন অপারেটিং সিস্টেম, অপারেটিং সিস্টেমে থাকা বিভিন্ন প্রোগ্রাম ও অনেক সময় ব্যবহারকারীকেও ফাইলের ধরন বুঝতে সাহায্য করে। যেমন

input.txt তে input হচ্ছে ফাইলের নাম এবং .txt হল ফাইল নেম এক্সটেনশন।

একটি ফাইলের data structure, স্ট্যান্ডার্ড I/O লাইব্রেরী stdio.h এ FILE নামক structure হিসাবে ডিফাইন করা আছে। FILE হচ্ছে একটি defined data type। FILE স্ট্রাকচারে ফাইল সম্পর্কে বিভিন্ন তথ্য জমা থাকে। সকল ফাইলকে তৈরী বা খোলার সময় একটি ফাইল পয়েন্টার ডিক্লেয়ার করতে হয় যা মেমরিতে ফাইলটির অবস্থান নির্দেশ করে এবং সেই ফাইল পয়েন্টারের data type হতে হবে অবশ্যই FILE। fopen() এর প্রোটোটাইপ দেখলেই আমরা বুঝতে পারবো যে fopen() ফাংশনও একটি পয়েন্টার রিটার্ন দেয় যার type হচ্ছে FILE।

ফাইল খোলার উদ্দেশ্য বা purpose বলতে বোঝায় ফাইলটি আমরা কি কাজে খুলছি। আমরা কি নতুন ফাইল তৈরী করছি? নাকি আগে থেকেই আছে এমন কোন ফাইলে ইনপুট দিতে চাচ্ছি? নাকি ফাইল থেকে স্রেফ ডেটা read করতে চাচ্ছি? fopen() ফাংশনের mode নামক প্যারামিটার আর্গুমেন্ট হিসেবে আমাদের কাছ থেকে এই উদ্দেশ্য জানতে চায়।

কাজেই mode নিয়ে আলোচনা আবশ্যক। নিচের ছক লক্ষ্য করঃ

"r"
* read করার জন্য ফাইল খোলা নির্দেশ করে। যদি ফাইল নেম এ উল্লেখ করা ফাইলটি আগে থেকেই না থাকে তাহলে এই mode এ fopen() কাজ করতে পারে না এবং NULL রিটার্ন করে। NULL হচ্ছে একটি invalid মেমরি এড্রেস।

"w"
* write করার জন্য ফাইল খোলা নির্দেশ করে।
* ফাইল নেম এ উল্লেখ করা ফাইলটি আগে থেকেই না থাকলে ফাইল টি নতুন করে তৈরী করা হয়।
* ফাইল নেম এ উল্লেখ করা ফাইলটি আগে থেকেই থাকলে ফাইলের সব ডেটা মুছে ফেলে write করার জন্য প্রস্তুত করা হয়।

"a"
* ফাইলে নতুন ডেটা append বা add করা নির্দেশ করে
* ফাইল নেম এ উল্লেখ করা ফাইলটি আগে থেকেই না থাকলে ফাইলটি তৈরী করা হয়
* ফাইল নেম এ উল্লেখ করা ফাইলটি আগে থেকেই থাকলে যে পর্যন্ত ফাইলে তথ্য আছে তার পর থেকে ফাইলে write অপারেশন চালানো হয়। পূর্বের ডেটা অপরিবর্তিত থাকে।

"r+" ও "w+"
* ফাইলকে read এবং write উভয়ই করা যায়
* তবে "r+" এর ক্ষেত্রে ফাইলটি আগে থেকে তৈরী না থাকলে নতুন করে ফাইলটি তৈরী করবে না, error দেখাবে।
* "w+" এর ক্ষেত্রে ফাইলটি আগে থেকে তৈরী না থাকলে নতুন করে ফাইলটি তৈরী করবে, এবং তৈরী থাকলে আগের সব ডেটা মুছে ফেলবে।

"a+"
* "a" এর মতই, শুধু read ও write উভয়ই করা যাবে

আমরা বলেছিলাম যে স্ট্রীম ২ ধরনের। টেক্সট ও বাইনারি। উপরের mode গুলো টেক্সট ডেটার জন্য। বাইনারি ডেটার জন্য সমতুল্য মোড গুলো হচ্ছে:

"rb" → "r"
"wb" → "w"
"ab" → "a"
"r+b" বা  "rb+" → "r+"
"w+b" বা "wb+" → "w+"
"a+b" বা "ab+" → "a+"

কাজেই একটি ফাইল তৈরী বা খোলার জন্য-

১. একটি ফাইল পয়েন্টার ডিক্লেয়ার করতে হবে যার data type হবে FILE
২. ফাইলের নাম ও mode কে আর্গুমেন্ট হিসেবে নিয়ে fopen() ফাংশন কল করতে হবে যা একটি ফাইল পয়েন্টার রিটার্ন করবে।
৩. প্রাপ্ত ফাইল পয়েন্টার টিকে ডিক্লেয়ার করা ফাইল পয়েন্টারে এসাইন করতে হবে।

উদাহরণস্বরূপ, আমরা যদি input.txt ফাইলটিকে নতুন করে তৈরী করে তাতে কিছু ডেটা write করতে চাই তাহলে

FILE *fp;
fp=fopen("input.txt","w");

কোডটি লিখতে হবে।

আবার যদি এমন হয় যে input.txt আগে থেকেই ছিলো এবং আমরা শুধু তার ডেটা read করতে চাই, তাহলে কোড হবে

FILE *fp;
fp=fopen("input.txt","r");

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

FILE *fp;
fp=fopen("input.txt","w");
if (fp==NULL)
printf("can not open file.\n");

অথবা

FILE *fp;
if ((fp=fopen("input.txt","w"))==NULL)
printf("can not open file.\n");

(to be continued...)

File I/O (ফাইল ইনপুট/আউটপুট) (continued.. Part 2)

ফাইলে ইনপুট / আউটপুট অপারেশন

Simple:
ইনপুট ফাংশন→ getc()/fgetc()/getw()
আউটপুট ফাংশন→ putc()/fputc()/putw()

High level:
ইনপুট ফাংশন→ fscanf()/fgets()
আউটপুট ফাংশন→ fprintf()/fputs()

Binary:
ইনপুট ফাংশন→ fread()
আউটপুট ফাংশন→ fwrite()

আজকের আলোচনায় কেবল simple ইনপুট আউটপুট  cover করা হবে। High level ফাংশন ও বাইনারি ইনপুট আউটপুট পরে আলোচিত হবে।

ফাইল খোলার পরে ফাইলে ইনপুট আউটপুট অপারেশন চালানো যায়। এখন থেকে ইনপুট অপারেশন কে read ও আউটপুট অপারেশন কে write বলা হবে।

সবচাইতে সিম্পল ইনপুট আউটপুট ফাংশন হচ্ছে getc()/fgetc() ও getw() ইনপুট এর জন্য এবং putc()/fputc() ও putw() আউটপুট অপারেশন এর জন্য। getc() ও fgetc() একই ফাংশন, ঠিক তেমনি putc() ও fputc()।

getchar() ও putchar() এর মত getc() ও putc() একটিমাত্র ক্যারেকটার নিয়ে কাজ করে। getc() ফাইল থেকে একটি মাত্র ক্যারেকটার read করে এবং putc() ফাইলে একটি মাত্র ক্যারেকটার write করে। getw() ও putw(), getc() ও putc() এর মতই, শুধু এরা একটি ইন্টিজার ভ্যালু read ও write করে।

getc()/fgetc() এর ফাংশন প্রোটোটাইপ হচ্ছে

int getc ( FILE *fp);

putc()/fputc() এর ফাংশন প্রোটোটাইপ হচ্ছে

int putc (int ch, FILE *fp);

putc(), ch ভ্যারিয়েবল এ উপস্থিত ক্যারেকটার টিকে *fp দ্বারা নির্দেশিত ফাইলে write করবে। ঠিক তেমনি যদি কোন char type এর ভ্যারিয়েবল এ getc() কে এসাইন করা হয় তাহলে, getc(), *fp দ্বারা নির্দেশিত ফাইলের প্রথম ক্যারেকটার টিকে read করবে এবং তার ভ্যালু char type এর ভ্যারিয়েবলটিতে জমা করবে। যেমন:

#include<stdio.h>

int main()
{
/* ফাইল পয়েন্টার ও একটি char ভ্যারিয়েবল ডিক্লেয়ার করা হল*/
FILE *fp;
char ch;

/* ফাইল পয়েন্টারে একটি ফাইল input.txt খোলা হল write করার জন্য। ফাইলটি সঠিকভাবে খোলা হল কি না তাও চেক করা হল*/
if((fp=fopen("input.txt", "w")==NULL)
   printf("can not open file.\n");

/* কিবোর্ড দ্বারা একটি ক্যারেকটার ইনপুট দেওয়া হল। এই ক্যারেকটার টিকে putc() ফাংশন ব্যবহার করে input.txt ফাইলে write করা হল*/
ch = getchar();
putc(ch, fp);

......
......
return 0;
}

উপরের কোডটি input.txt নামে একটি ফাইল write করার জন্য খুলবে এবং কিবোর্ড থেকে একটি ক্যারেক্টার ইনপুট নিয়ে তাকে ফাইলে write করবে।

আবার,

#include<stdio.h>

int main()
{
/*ফাইল পয়েন্টার ও একটি char ভ্যারিয়েবল ডিক্লেয়ার করা হল*/
FILE *fp;
char ch;

/* ফাইল পয়েন্টারে read করার জন্য input.txt ফাইলটি খোলা হল এবং সঠিক ভাবে খোলা হল কি না তা চেক করা হল*/
if((fp=fopen("input.txt", "r")==NULL)
    printf("can not open file.\n");

/*getc() ফাংশন ব্যবহার করে ফাইলের প্রথম ক্যারেকটার টি read করা হল এবং তাকে char ভ্যারিয়েবল এ এসাইন করে প্রিন্ট করে দেখা হল যে read সফল হয়েছে*/
ch = getc(fp);
putchar(ch);

.......
.......
return 0;
}

উপরের কোডটি input.txt ফাইলটি read করার জন্য খুলবে এবং একটি ক্যারেক্টার read করে ভ্যারিয়েবল ch এ জমা করবে এবং তাকে স্ক্রীনে প্রিন্ট করে দেখাবে।

fp একটি ফাইল পয়েন্টার। তারমানে এটি একটি মেমরি এড্রেস মাত্র। প্রতি read ও write অপারেশন এর পরে fp এর মান এক ক্যারেক্টার পরিমান বৃদ্ধি পায়। তাই আমরা যদি লুপ ব্যবহার করে ক্রমাগত ইনপুট নিতে থাকি getc() এর মাধ্যমে বা ক্রমাগত আউটপুট দিতে থাকি putc() এর মাধ্যমে তাহলে একই ক্রমে ফাইলে read বা write চলতে থাকবে। তবে-

EOF দ্বারা ফাইলের সমাপ্তি বোঝানো হয়। এটি ফাইলের শেষ প্রান্ত নির্দেশ করে। windows OS এ Ctrl-Z দ্বারা EOF লিখা যায় (Ctrl-Z চাপলে স্ক্রিনে ^z প্রিন্ট হয়)। C ল্যাংগুয়েজ এ EOF হচ্ছে একটি ঋণাত্মক ইন্টিজার (সাধারণত -1)। getc() ব্যবহার করার সময় getc() ততক্ষণ পর্যন্ত read করতে পারে যতক্ষন ফাইলের সমাপ্তিতে না পৌছানো হয়। ফাইলের সমাপ্তিতে পৌছালে getc() রিটার্ন ভ্যালু হিসাবে EOF রিটার্ন করে।

উদাহরণস্বরূপ :

FILE *fp;
char ch;

if((fp=fopen("input.txt","w")==NULL)
    printf("can not open file.\n");

while ((ch=getchar())!= EOF)
    putc(ch, fp);

উপরের কোডটি যতক্ষন পর্যন্ত কিবোর্ডে Ctrl-z চাপা না হবে ততক্ষন পর্যন্ত কিবোর্ড থেকে ইনপুট নিয়ে input.txt ফাইলে write করতে থাকবে।

আবার,

FILE *fp;
char ch;

if((fp=fopen("input.txt", "r")== NULL)
    printf("can not open file. \n");

while ((ch= getc(fp))!= EOF)
    printf("%c", ch);

উপরের কোডটি input.txt ফাইলটি প্রথম থেকে শেষ পর্যন্ত read করে স্ক্রিনে আউটপুট দিবে।

getc() ফাংশন সঠিক ভাবে কাজ না করতে পারলে বা ফাইলের শেষ প্রান্তে পৌছালে EOF রিটার্ণ করে।
putc() ফাংশন সঠিকভাবে কাজ না করলে EOF রিটার্ন করে।

ফাইল বন্ধ করা

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

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

ফাইল বন্ধ করার জন্য fclose() ব্যবহার করা হয়। fclose() এর ফাংশন প্রোটোটাইপ হচ্ছে

int fclose(FILE *fp);

fclose() সঠিকভাবে সম্পন্ন না হলে EOF রিটার্ণ আসে অন্যথায় শূন্য রিটার্ন আসে।

নিচের উদাহরনে আমরা test.txt ফাইলটি তৈরী করে তাতে কিবোর্ড থেকে ইনপুট নিয়ে write করবো এবং এরপরে read করে স্ক্রিনে আউটপুট দিয়ে দেখবো যে আমাদের ইনপুট ঠিক হয়েছে কি না। কিবোর্ডের ইনপুট তখন শেষ হবে যখন আমরা Ctrl-z চাপবো।

#include<stdio.h>

int main()
{
FILE *fp;
char ch;

fp=fopen("test.txt", "w");

while ((ch= getchar())!= EOF)
    putc(ch, fp);

fclose(fp);

fp=fopen("test.txt", "r");

while ((ch=getc(fp))!= EOF)
    printf("%c", ch);

fclose(fp);

return 0;
}

উপরের প্রোগ্রামে কোন ধরনের error checking করা হয় নি। error checking সহ প্রোগ্রামটি হবে নিম্নরূপ। exit() ফাংশনটি হচ্ছে তৎক্ষণাৎ প্রোগ্রাম থামিয়ে দেওয়ার জন্য।

#include<stdio.h>

int main()
{
FILE *fp;
char ch;

if ((fp=fopen("test.txt", "w")==NULL)
{
    printf("error opening file.\n");
    exit(1);
}
while ((ch= getchar())!= EOF)
    putc(ch, fp);

if(fclose(fp)==EOF)
{
    printf("error closing file.\n");
    exit(2);
}

if ((fp=fopen("test.txt", "r")==NULL)
{
    printf("error opening file.\n");
    exit(1);
}

while ((ch=getc(fp))!= EOF)
    printf("%c", ch);

if(fclose(fp)==EOF)
{
    printf("error closing file.\n");
    exit(2);
}

return 0;
}

C ভাষায় লেখা একটি প্রোগ্রামের সাধারন গঠন

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

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

/*এটি একটি সাধারণ C প্রোগ্রাম। */

#include<stdio.h> /*প্রিপ্রসেসর ১ঃ লিংক সেকশন বা হেডার ফাইল*/


#define x y /*প্রিপ্রসেসর ২ঃ গ্লোবালল ডেফিনিশন সেকশন বা ম্যাক্রো ডিক্লেয়ারেশন (অপশনাল)*/


......; /*গ্লোবাল ভ্যারিয়েবল ডিক্লারেশন (অপশনাল)*/


int main() /*প্রোগ্রামের মূল ফাংশন যার ভেতরে প্রোগ্রামের মূল কাজ গুলো সম্পন্ন হবে*/

{

....; /* লোকাল ভ্যারিয়েবল ডিক্লারেশন*/


....; /* ইনপুট ফাংশন*/


....; /* হিসাব নিকাশ*/


....; /* আউটপুট ফাংশন*/


return 0;

}


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

একেবারে শুরুতে আছে,

/*এটি একটি সাধারণ C প্রোগ্রাম। */

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

এর পরেই আছে,

#include<stdio.h> /*প্রিপ্রসেসর ১ঃ লিংক সেকশন বা হেডার ফাইল*/

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

এর পরের লাইনে আছে,

#define x y /*প্রিপ্রসেসর ২ঃ গ্লোবালল ডেফিনিশন সেকশন বা ম্যাক্রো ডিক্লেয়ারেশন (অপশনাল)*/

অংশটি। এখানে আরেকটি প্রিপ্রসেসর ডিরেক্টিভ দেখানো হয়েছে define। এটি সিম্বলিক কনস্ট্যান্ট বা ম্যাক্রো ডিফাইন করার জন্য ব্যবহৃত হয়। #define এর পরে একটি স্পেস দিয়ে ম্যাক্রো বা কনস্ট্যান্ট টি সেট করা হয় এবং এর পরে আরেকটি স্পেস দিয়ে ঐ ম্যাক্রো বা কনস্ট্যান্ট এর মান সেট করা হয়। আমাদের মূল প্রোগ্রামে যদি কোটেশন মার্ক (" ") এর মধ্যে ছাড়া অন্য কোথাও ঐ কনস্ট্যান্ট বা ম্যাক্রোটি থাকে তাহলে তা কম্পাইলেশন এর আগেই তার মান দ্বারা প্রতিস্থাপিত হয়ে যাবে। যেমনঃ এই কোডের ডিরেক্টিভ অনুযায়ী প্রোগ্রামে যদি কোন x থাকে তাহলে কম্পাইলেশনের আগেই তা y দ্বারা প্রতিস্থাপিত হবে। কমেন্ট খেয়াল করেন যে এটি অপশনাল। তাই এটি কেবল দরকারে ব্যবহৃত হবে। সব সময় নয়।

এরপরের অংশে আছে,

......; /*গ্লোবাল ভ্যারিয়েবল ডিক্লারেশন (অপশনাল)*/

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

এর পরের লাইনে হচ্ছে আমাদের প্রোগ্রামের main() ফাংশন ডিফাইন করার ধাপ যা

int main() /*প্রোগ্রামের মূল ফাংশন যার ভেতরে প্রোগ্রামের মূল কাজ গুলো সম্পন্ন হবে*/

{

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

এর পরের লাইন সমূহ,

....; /* লোকাল ভ্যারিয়েবল ডিক্লারেশন*/


....; /* ইনপুট ফাংশন*/


....; /* হিসাব নিকাশ*/


....; /* আউটপুট ফাংশন*/

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

সব শেষে আছে

return 0;

}

অংশটি। main() ফাংশনের রিটার্ন টাইপ অনুযায়ী return ব্যবহার করা হয়। যেহেতু আমাদের ব্যবহৃত ফাংশনটি int main() সেহেতু এখানে শূন্য (0) কে রিটার্ন দেওয়া হয়েছে। return সম্পর্কে এখানে বিস্তারিত পড়ুন।

return থাকার কারণে 0 এর পরের সেমিকোলন ই হবে প্রোগ্রামের সমাপ্তি। তবে কোন কারণে যদি return অনুপস্থিত থাকে তাহলে ক্লোজিং ব্রেস '}' টি প্রোগ্রামের সমাপ্তি নির্দেশ করবে।

অনেক আলোচনা হল, এবার কিছু উদাহরণ দেখা যাক।

/* উদাহরণ ১) এই প্রোগ্রামটি "C Program" লেখাটি আউটপুট দিবে।*/


#include<stdio.h>


int main()

{

printf("C Program");


return 0;

}


লক্ষ্য কর যে এইখানে কোন ভ্যারিয়েবল ডিক্লেয়ার করা হয় নাই, কোন ইনপুট নেওয়া হয় নাই, কোন হিসাব করা হয় নাই। শুধু আউটপুট ফাংশন printf() ব্যবহার করা হয়েছে। আবার,


/* উদাহরণ ২) এই প্রোগ্রামটি একটি সংখ্যা ইনপুট নিয়ে তাকে আউটপুট দিবে।*/


#include<stdio.h>


int main()

{

int number;  /*ইন্টিজার টাইপের লোকাল ভ্যারিয়েবল number কে ডিক্লেয়ার করা হল*/


scanf("%d", &number); /* ইনপুট ফাংশন */


printf("%d", number); /* আউটপুট ফাংশন */


return 0;

}

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

টেস্ট কেস : ইহা কি এবং ইহার কাজ কি?

কম্পিটিটিভ প্রোগ্রামিং এ যারা আমার মত নতুন তারা একটা জিনিস সহজে বুঝতে পারেন না আর সেটা হল Test Case

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

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

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

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

#include<stdio.h>

int main()
{
    int a, b, i, sum, T;

    scanf("%d", &T); /* টেস্টকেস ইনপুট নেওয়া হল*/

    for (i =1; i <=T; i++) /* টেস্ট কেসে লুপ */
    {
/* মূল সমস্যার কাজ শুরু এখানে */
        scanf("%d%d", &a, &b);
        sum= a+b;
        printf("%d\n", sum);
/* মূল সমস্যার কাজ শেষ এখানে */
    }
    return 0;
}

এই কাজটা while স্টেটমেন্ট দিয়েও করা যায়। যেমন,
#include<stdio.h>

int main()
{
    int a, b, sum, T;

    scanf("%d", &T); /* টেস্টকেস ইনপুট নেওয়া হল*/

    while (T--) /* টেস্ট কেসে লুপ */
    {
/* মূল সমস্যার কাজ শুরু এখানে */
        scanf("%d%d", &a, &b);
        sum= a+b;
        printf("%d\n", sum);
/* মূল সমস্যার কাজ শেষ এখানে */
    }
    return 0;
}

কাজেই টেস্ট কেস এর জন্য আমাদের একটা লুপ নিতে হবে যার মধ্যে প্রব্লেম স্টেটমেন্ট এ উল্লিখিত সমস্যার সমাধান এর কোড (ইনপুট, প্রসেসিং এবং আউটপুট)  থাকবে।

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

CECP - নামতা শিক্ষা

নামতা শিখতে কার না কষ্ট হয়েছে। মুখস্থ, মুখস্থ আর মুখস্থ। বিশিষ্ট কম্পিউটার প্রোগ্রামার জুবায়ের চায় না তার সন্তানকে বই থেকে নামতা মুখস্থ করতে হোক। সে ভেবে রেখেছিলো সময় পেলেই সে একটি প্রোগ্রাম তৈরী করে ফেলবে যা কোন সংখ্যা ইনপুট দিলেই তার নামতা আউটপুট দিবে। যেমন, যদি ইনপুট দেওয়া হয় ১০০ তাহলে আউটপুট হবে ১০০x১=১০০, ১০০x২=২০০,.....
১০০x১০=১০০০।

সময়ের অভাবে জুবায়ের এটা বানাতে পারেনি, অথচ তার সন্তান বড় হয়ে যাচ্ছে। আপনি কি জুবায়েরকে সাহায্য করতে পারেন?

ইনপুট

প্রথম লাইনে একটি মাত্র ইন্টিজার বা পূর্ণ সংখ্যা T ইনপুট হবে যা টেস্ট কেস সংখ্যা নির্দেশ করবে। এর পরে T সংখ্যক লাইনে প্রতি লাইনে ১ টি করে পূর্ণ সংখ্যা m ইনপুট হবে।
১<=T<=১০০; ১< m <= ২^৩১;

আউটপুট
T সংখ্যক আউটপুট হবে। প্রত্যেক টেস্ট কেসের জন্য প্রথমে কেস নম্বর ও তারপর ১০ টি করে লাইন প্রিন্ট হবে। অর্থাৎ প্রত্যেক টেস্ট কেসের জন্য মোট ১১ টি লাইন প্রিন্ট হবে। আউটপুট ফরম্যাট হবে:

Case x:
m * i = a

যেখানে x হবে কেস নম্বর, i হবে 1 থেকে 10 পর্যন্ত এবং a হবে m ও i  এর গুনফল। ভাল করে বোঝার জন্য স্যাম্পল ইনপুট আউটপুট দেখুন।