Tuesday 24 December 2013

কৈশরের প্রেম আমার C: ২য় পর্ব: input types


কি
 খবর সবার?  আজকে আবার বসে পরলাম C এর কয়েকটা বিষয় দেখার জন্য। কয়েকদিন ধরেই একটা ব্যাপার নিয়ে বসবো ভাবছিলাম। যেটা বেশি মনের মধ্যে খোচাচ্ছিলো যে কোডিং এর সময় শুরুর দিকে অনেক কিছু ওভারলুক করে যেতাম, তখন খুব বেশি কোনো সমস্যাও হতো না, দুই একটা ওয়ারনিং খেতাম ঠিকই কিন্তু কোডটা তো run করতো! আর কি লাগে !? :P এখন যখন কোডিং কে বোঝার চেষ্টা করি যখন দেখি AC পাওয়াটাই যখন সবার ধ্যান-ঞ্জান বা কোডের efficiency বাড়ানোর চেষ্টায় কোডকে আরো আরো 'সুন্দর' করার চেষ্টা সবার, তখন ভাবি দুই একটা নতুন টেকনিক বা keyword বা আগের জানা keyword এর অজানা ব্যবহার শিখে যদি আমারই লেখা কোডটার মান world 
class কোন প্রোগ্রামারের লেখা কোডের মানের আরেকটু কাছাকাছি নিতে পারি তো সমস্যা কি আরেকটু সময় দিতএর পিছে!! কামার যখন গায়ে মাথায় মুখে কাদা মাখামাখি করে একটা কিছু পারফেক্টলি বানিয়ে ফেলেসারাদিন খেটে দিন শেষে নিজের বানানো শিল্পকে দেখে যে আনন্দটা পায়সুযোগ থাকতে নিজেকে কেন সেই অসাধারন আনন্দ থেকে দূরে সরিয়ে রাখবো!! 

আচ্ছা অনেক কথা হল, কাজের কথায় আসা যাক। গত কয়েক দিনে মোটামোটি ৩টা বিষয়ের ম্যাটেরিয়াল যোগার করলাম একটা একটা করে লিখবো, তো আজকে শুধু input 
system টা নিয়েই কথা বলি চেষ্টা করবো দুইটা segment এর মধ্যে আমার জানা যত বেশি সম্ভব scanf এর type গুলাকে কভার করতে। শুরুতে contest গুলাতে স্বাধারনত কি কি ধরনের input নেয়ার কথা বলা থাকে সেগুলা বলবো, আর এর ফাকে ফাকে দরকারি বাদ বাকি আনুষাংগিক বিষয় গুলা দেখবো। তো চল শুরু করা যাকঃ


কেস : ধর যদি প্রশ্নে বলা থাকে, “There will be two integers in every line of the input and terminated by EOF (end of file).”
এখানে যেটা বলা হয়েছে তা হল পুরা কোডটা কাজ করবে শুধু এবং শুধমাত্র ২টা integer কে input নেয়ার পর। খানিকটা এমন ভাবেঃ
int a,b;
            while(scanf("%d %d",&a,&b)==2) //take 2 integer, perfectly checked
            {
                        // rest of the work
            }
** হাতে সময় থাকলে EOF টার ব্যাপারে একটু google বসার চেষ্টা করলে ভাল হয়।


কেস : প্রশ্নে যদি  বলা থাকে, “There will be three numbers (not necessarily integers) in every line of input and terminated by EOF (end of file).”

কি বলা হয়েছে বুঝতেই পারছো আশা করি। কোড স্কেলিটনটা খানিকটা এমন ভাবে হতে পারেঃ
double a,b,c;
while(scanf("%lf %lf %lf",&a,&b,&c)==3) //3 inputs are taken perfectly with correct data type
            {
                        // rest of the work
            }

** ছোট্ট একটা প্রশ্ন, এখানে double এর বদলে অন্য কোনো data type হলে কি সমস্যা হত? হাতে সময় থাকলে google করে খুজে বের করতে পারো। চেষ্টা করবো নেক্স কোনো পোস্টে এটা নিয়ে কথা বলতে।


কেস : যদি প্রশ্নে বলা থাকে, “There will be 3 integers and one name (not consisting of any space) and the input will be terminated if the given first integer is 0”

স্কেলিটন কোড:
int a,b,c;
            char nam[100];
            while(scanf("%d %d %d %s",&a,&b,&c,nam)==4)
            {
                        if(a==0)
                                    break;
                        // rest of the work
            }

আচ্ছা এখন আরো কয়েকটা কেস দেখার আগে input নেয়ার জন্য scanf  এর একটা বড়সড় বাউন্ডারি দেখে আসি। তার আগে নিচের কোডটা রান করে, ‘i 
am programmer’  input নিয়ে দেখ output টা কি আসে। পুরান পাগলদের বলিএই পিচ্চি প্যারাটা থেকে দূরে থাকতে পারেন :পি
#include<cstdio>

int main()
{
            char nam[100];
            scanf("%s",&nam);
            printf("%s",nam);
}
সমস্যাটা কি আশা করি বুঝে গেছ, তারপরও একটু বলি scanf কোনো space দেখলেই executed হয়ে যায়। তাই সে i এর পরে আর কিছু আসলে আমলেই নেই নি। এখানে আরো কিছু কথার ব্যাখ্যা এসে যায়, কিন্তু এই আর্টিকেলটাকে শুধু নতুনদের জন্য লিখছি, তাই খামাখা কঠিন কিছু লিখতে ইচ্ছা করছে না। তো যারা এই কোডটা কেমন করে ঠিক করে run করানো যায় google করতে যাচ্ছ, তাদের কাজ একটু কমিয়ে দেই। নিচের কোডটা দেখঃ
#include<cstdio>

void main()
{
            char nam[100];
            gets(nam);
            puts(nam);
}
আর যাদের এইটাতে পেট ভরে নি তাদের জন্য scanf  দিয়েই আরেকটাঃ
#include<cstdio>

int main()
{
            char n[10];
            scanf("%[^\n]",&n);
            printf("%s\n",n);
} 
a. তো gets() যখন এসেই পড়ল, একে নিয়ে কয়েকটা কথা বলা যাক। 
  1. যখন char নিয়ে কাজ করতে হয় আর সেখানে space কে নিয়ে ডিল করার চান্স থাকে, gets() ব্যবহার করাটাই ভাল, তাতে syntax নিয়ে বেশি চিন্তা করে সময় নস্ট করার সম্ভাবনা কম হয়।
  2. সফলভাবে run করা gets() কে argument pointer হিসেবে কাজ করে বিশদ ভাবে না বলে খুব অল্প কথায় এই কোডটা দেখতে পারো
#include<cstdio>
int main()
{
            char n[77], *b;
            b=gets(n);
            printf("%s\n",b);
}
এখানে আদিকালের রীতি অনুসারে input  নেয়ার শুরুতে b পয়েন্ট করে n[0] কে
আচ্ছা gets() এর কথা যখন বলছি  gets() এর আরো কয়েকটা রুপ দেখে নেই চলো এদের সবাই কে রেগুলার ব্যবহার করতেই হয় তা না। লজিকের প্রয়োজনে এদের দরকার পরে মাঝে মধ্যে তবে একটা জিনিস খেয়াল রেখো getch() এর শাখা গুলা  non ANSI compliant, সব compiler  যে এদের সাপোর্ট করবে এমন কোনো নিশ্চয়তা নাই চলো দেখি তাহলেঃ


b. getc(): এটা কোনো automatic function process না তাই stream (sequence of characters) থেকে char input নেয়, অনেকটা getchar() এর মত।এটাঃ  
  1. macro হিসেবে কাজ করতে পারে
#include<cstdio>

int main()
{
            char c;
            printf("Input a character:");
            c= getc(stdin);
            printf("The character input was: '%c'\n", c);
}

c. fgetc(): এটা অনেকটাই getc() এর মত কিন্তু এটা function হিসেবে কাজ করেএটাঃ
  1.  macro হিসেবে কাজ করতে পারে না
  2. যেহেতু এটা function হিসেবে কাজ করে। তাই সহজেই এর address বের করা যায়ফলে একটা function এর address অন্য function  argument pass হিসেবে পাঠানো যায়
  3. fgetc() কে call করতে একটা function বা getc() কে call করার থেকে বেশি সময়ের দরকার পরে
 

d. getch():একটাই character কে input  নেয়। বিশেষত্ব হচ্ছে-  
  1. এটা কখনো enter কমেন্ডের জন্য অপেক্ষা করে না 
  2.  input নেয়া char কে prompt screen  echo করে না
#include<cstdio>
#include<conio.h>
int main()
{
   printf("Enter a character:");
   getch();
   printf("\n\n");
}

e. getche():  শেষে একটা অতিরিক্ত e দেখে বুঝে ফেলা যায় যে getch() আর getche() একি জিনিস, শুধু এটা 
  1. prompt screen  input নেয়া char কে echo করে
#include<cstdio>
#include<conio.h>
int main()
{
   printf("Enter a character:");
   getche();
   printf("\n\n");
}

f. getchar(): ইনি আগের অন্যদের চেয়ে একটু আলাদা। command prompt দিয়ে input নেয়ার সময় সবগুলা char কে buffer প্রক্রিয়ার মধ্যে আটকে রেখে enter এর জন্য অপেক্ষা করতে থাকে। enter কমেন্ড পাওয়ার পর input কে read করা শুরু করে। আর তারপরে screen  echo করতে পারে
#include<cstdio>

int main()
{
   int c;
   c= getchar();
   putchar(c);
}

অনেক বড় হয়ে গেল না? আসলে এগুলা এক জায়গায় লেখা থাকলে পরে কখনো দরকার বারবার অনেক কিছু ঘাটাঘাটি না করে, এক জায়গায় চেক করলেই পাওয়া যায় সেভাবে গুছিয়ে রাখতে চাচ্ছি। তো এখন gets() আর তার বাচ্চা কাচ্চাদের গল্প আজকে এই পর্যন্তই থাকুক। দরকার পরলে আবার পরে দেখা যাবে। আপাতত কেস  এর দিকে আগাতে থাকিঃ

কেস : যদি প্রশ্নে দেয়া থাকে, “There will be one or more names in a single line and will be terminated by end of file”

কোডটা হতে পারেঃ
char line[100];
            while(gets(line))
            {
                        // rest of the work
            }

কেস : যদি কখনো এমন প্রশ্ন পাও যে, “Suppose there are three integers in a string (array of characters), how will you take the three integers in separate variables?

একটু ঝামেলা আছে এটা, কনটেস্টে খুব সহজ সহজ প্রবলেমগুলার মধ্যে এই ধরনের ঝামেলা যোগ করে দেয় মাঝেমধ্যেই। এই কেসটার জন্য scanf  এর একটা type sscanf ব্যবহার করা যায়।

a. sscanf: scanf  আর sscanf  প্রায় একই রকমের কাজ করে, পার্থক্যটা হচ্ছে scanf input  নেয় standard input system থেকে, আর sscanf input নেয় string থেকে। আর বাদ বাকি কাজকারবার সব এক। তো আমাদের কেস  এর জন্য আমরা sscanf  ব্যবহার করতে পারি।

কেস  এর জন্য sscanf  এর কোডের একটা নমুনা হতে পারেঃ
#include<cstdio>

int main()
{
    char sen[100]={"i'm 6.2 feet tall"};
    char n[10];
    float i;
    
    sscanf(sen,"%s %f",n,&i);
    printf("%s %.1f\n\n",n,i);
}
আচ্ছা চল scanf এর আরেকটা আন্ডাবাচ্চাকে দেখে আসি একটা যখন দেখলাম সেটার আরেকটা বাচ্চাকে বাদ রেখে লাভ কিঃ

b. scanf_s: scanf  আর scanf_s হচ্ছে দুই সেই দুই নারীর মত যারা দুইজনই সুন্দরী, কিন্তু এদের একজন ঘর গুছাতেও জানে সমস্যা যদি থেকে থাকে তো  মাইক্রোসফট এলাকার মাইয়া। উদাহরণ দিয়ে বলছিঃ
            char valonam[10]; //একটা  array ডিক্লেয়ার করলাম যেটা ১০টা ক্যারেক্টার নিতে পারবে
            scanf("%s", valonam); //একটা string input নিচ্ছি

এখন যদি কেরো নাম  ডিজিটের মধ্যে হয়, তাহলে কোনো সমস্যা নাই, কিন্তু তার বেশি হলে? আসলে তখনও এক ভাবে কোনো সমস্যা হবে না, scanf   তখন valonam এর জন্য বরাদ্দ মেমরির পর ডিভাইসের মূল মেমরি থেকে জায়গা টানবে। এতদূর পর্যন্ত কোনো সমস্যাই নাই। কিন্তু মেইন মেমরির থেকে নেয়া জায়গাটা যখন অন্য কেউ ব্যবহার করতে চাবে তখন এই প্রোগ্রামটা ক্র্যাস করবে।তাই scanf_s এর আবির্ভাব, scanf_s অপারেসনের সময় চেক করে দেখবে input টা বরাদ্দকৃত জায়গায় আটবে কিনা এর জন্য scanf_s ব্যবহার করা কিছুটা হলেও সিকিওরড।
#include<cstdio>

int main()
{
            int v;//[10];
            scanf_s("%i",&v);
            printf("%i\n",v);
}

একটা কথা মনে পরল এখানে না লিখে আলাদা করে লিখলে মনে হয় ভাল হত, কোথায় লিখবো বুঝছিনা। এখানেই বলি, %s format specifier ওয়ালা যত scanf  এর রুপভেদ আছে তাদের কেউ আসলে সিকিওরড না। বাফার রিলেটেড প্রবলেম। চাইলে বিস্তারিত খুজতে পারেন।


কেস : যদি প্রশ্নে থাকে, “In each line there will be 2 integers and one name (consisting space) and the input will be terminated if the given first integer is 0. All variables are separated by exactly one space”

Sample Input:
1 7 Cristiano ronaldo
2 10 liuz Suarez

এই প্রবলেমটার কোডটা হতে পারেঃ
#include <cstdio>

int main()
{
            int p,q;
            char nam[100];
            while(scanf("%d %d",&p,&q)==2)
            {
                        if(p==0) break;
                        getchar(); //required to remove the space
                        gets(nam);

                        // rest of the work
            }
}

কেস : যদি প্রশ্ন হয় এমন, There will be 2 integers in a line and one name (consisting space) on the next line and the input will be terminated by end of file.

Sample Input:
1 50 jose Mourinho
2 75 alex Farguson

প্রবলেমটার কোডটা হতে পারেঃ
#include <cstdio>

int main()
{
       int p,q;
       char nam[100];
       while(scanf("%d %d",&p,&q)==2)
       {
              getchar(); //required to remove the space
              gets(nam);

              // rest of the work
       }
}

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

শেষে যাদের কাছ থেকে প্রত্যক্ষ বা পরোক্ষভাবে সাহায্য পেয়েছি নিচে সবার নাম বা লিংক দিয়ে ধন্যবাদ জানাচ্ছি। ধন্যবাদ :)