সূচিপত্র

স্ট্রিং বলতে বুঝায় কয়েকটি ক্যারেক্টারের একটা সিকুয়েন্স। প্রকৃতপক্ষে সি-তে স্ট্রিং বলতে কিছু নেই। তাই আমাদের কাজ চালাতে হবে একটি ক্যারেক্টার অ্যারে নিয়ে। আমরা প্রথমেই দেখে নি একটা স্ট্রিং অ্যারেতে কীভাবে থাকে। আমরা ধরে নি, আমাদের কাছে ১৮ উপাদানের একটি ক্যারেক্টার অ্যারে আছে। এবং আমরা আমাদের এই অ্যারেতে “I LOVE BANGLADESH” কথাটি রাখতে চাই।

‘I’ ‘ ‘ ‘L’ ‘O’ ‘V’ ‘E’ ‘ ‘ ‘B’ ‘A’ ‘N’ ‘G’ ‘L’ ‘A’ ‘D’ ‘E’ ‘S’ ‘H’ ‘\0’

এখানে শেষের ‘\0’ খেয়াল কর। এটাকে বলা হয় নাল (NULL) ক্যারেক্টার। এটা স্ট্রিং-এর শেষ নির্দেশ করে। অর্থাৎ প্রতিটা স্ট্রিং-এর শেষে একটি নাল ক্যারেক্টার থাকবে। তাহলে আমরা একটা স্ট্রিং বানাতে পারি নিচের মত করেঃ

#include <stdio.h>
int main() {
    char sentence[18];
    sentence[0] = 'I';
    sentence[1] = ' ';
    sentence[2] = 'L';
    sentence[3] = 'O';
    sentence[4] = 'V';
    sentence[5] = 'E';
    sentence[6] = ' ';
    sentence[7] = 'B';
    sentence[8] = 'A';
    sentence[9] = 'N';
    sentence[10] = 'G';
    sentence[11] = 'L';
    sentence[12] = 'A';
    sentence[13] = 'D';
    sentence[14] = 'E';
    sentence[15] = 'S';
    sentence[16] = 'H';
    sentence[17] = '\0';
    return 0;
}

তবে এত কষ্ট না করে আমরা এটা এক স্টেটমেন্টেই করে ফেলতে পারি নিচের মতঃ

char sentence[18] = “I love Bangladesh”

স্ট্রিং

এক্ষেত্রে কম্পাইলার নিজ দায়িত্বে শেষের নাল ক্যারেক্টারটা লাগিয়ে নিবে।

খেয়াল কর, character আবদ্ধ করে রাখা হয় দু’টি দিয়ে, আর স্ট্রিং আবদ্ধ থাকে দুইটা -এর মধ্যে।

আবার, এভাবে সরাসরি স্ট্রিং দিয়ে ইনিশিয়ালাইজ করার সময় অ্যারেটার সাইজ বলে না দিলেও হয়। যেমনঃ

char sentence[] = “I Love Bangladesh”

এক্ষেত্রে কম্পাইলার নিজেই বুঝে নিবে অ্যারেটার সাইজ কত হবে এবং, শেষে একটা নাল ক্যারেক্টার লাগিয়ে দিবে!

এবার দেখা যাক, আমরা এই স্ট্রিং-টা প্রিন্ট করবো কীভাবে। স্ট্রিং-এর স্পেসিফায়ার হল %s

তাহলে আমরা কোডটা লিখে ফেলি!

#include <stdio.h>
int main() {
    char str1[] = "I Love Bangladesh";
    printf("%s\n", str1);
    char str2[18] = "I love my country";
    printf("%s\n", str2);
    char str3[100] = "I love my country, Bangladesh";
    printf("%s\n", str3);
    return 0;
}

এখানে আমরা দুই ভাবে স্ট্রিং ইনিশিয়ালাইজ করেই প্রিন্ট করে দেখলাম। এছাড়াও তৃতীয় উদাহারণে আমরা স্ট্রিং-এর সাইজ প্রয়োজনের চেয়ে বেশি দিয়েছি। কিন্তু শেষে নাল ক্যারেক্টার থাকার কারণে প্রিন্ট করার সময় কোনো সমস্যা হয় নি! এবার আমরা দেখি নাল ক্যারেক্টার না থাকলে কী হত।এ জন্য আমরা ফিরে যাব পর্বের প্রথম উদাহারণটিতে।

আমরা এবার নাল ক্যারেক্টারটা দিব না আর।

#include <stdio.h>
int main() {
    char sentence[100];
    sentence[0] = 'I';
    sentence[1] = ' ';
    sentence[2] = 'L';
    sentence[3] = 'O';
    sentence[4] = 'V';
    sentence[5] = 'E';
    sentence[6] = ' ';
    sentence[7] = 'B';
    sentence[8] = 'A';
    sentence[9] = 'N';
    sentence[10] = 'G';
    sentence[11] = 'L';
    sentence[12] = 'A';
    sentence[13] = 'D';
    sentence[14] = 'E';
    sentence[15] = 'S';
    sentence[16] = 'H';
    printf("%s\n", sentence);
    return 0;
}

কোডটা রান করলে দেখবা, আমাদের কাঙ্ক্ষিত ” I LOVE BANGLADESH”-এর পরও কিছু উল্টাপাল্টা ক্যারেক্টার দেখাচ্ছে।

Snap 2015-08-06 at 14.40.00

এর কারণ হল, আমরা “I LOVE BANGLADESH”-এর শেষে নাল ক্যারেক্টারটা দি নাই। এ কারণে কম্পাইলার বুঝতে পারে নি স্ট্রিং-টির শেষ কোথায়। তাই “I LOVE BANGLADESH”-এর পরো কিছু গার্বেজ ক্যারেক্টার প্রিন্ট করে দিয়েছে! এবং শেষে কোনো এক গার্বেজ ক্যারেক্টার ‘NULL’ হওয়ার কারণে সেখানে স্ট্রিং-টির শেষ ধরে নিয়েছে।

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

#include <stdio.h>
int main() {
    char str[20];
    scanf("%s", str); // & nai!
    printf("%s\n", str);
    return 0;
}

এই কোডে “Shoshikkha” ইনপুট দিলে আউটপুট নিচের মত।

Snap 2015-08-06 at 14.47.55

তবে তুমি যদি স্পেস সহ একটা স্ট্রিং এভাবে ইনপুট নিতে চাও, তাহলে দেখবে ইনপুট ঠিক মত নিচ্ছে না।

Snap 2015-08-06 at 14.49.35

অর্থাৎ, এক্ষেত্রে শুধু স্পেসের আগের অংশটাই ইনপুট নিচ্ছে! এর কারণ হল, scanf স্পেসকে “এন্টার” হিসেবে কাউন্ট করে। এই সমস্যার সমাধান হল gets() ফাংশন ব্যবহার করা। সেটা সম্পর্কে একটু পরে বলছি। আপাতত আমরা  স্ট্রিং নিয়ে কিছু কাজ করে নি!

প্রথমেই আমরা কাজ করবো স্ট্রিং-এর দৈর্ঘ্য নিয়ে। অর্থাৎ, একটি স্ট্রিং-এ কতটি ক্যারেক্টার আছে (নাল ছাড়া), সেটা আমরা বের করবো। এজন্য আমাদেরকে একটি লুপ চালিয়ে দিতে হবে, যেটা নাল ক্যারেক্টারে গিয়ে শেষ হবে। তো কথা না বাড়িয়ে কোডটা লিখে ফেলা যাক!

#include <stdio.h>
int main() {
    char str[] = "This is a random string!";
    int i, counter;
    for (i=0;str[i] != '\0';i++) {
        counter++;
    }
    printf("There are %d characters in the string!\n", counter);
    return 0;
}

কোডটা রান করলে দেখবা ঠিক মত আউটপুট দিচ্ছে না। বল তো কেন? একটু চিন্তা কর এটা নিয়ে, অন্তত পাঁচটি মিনিট।

আউটপুট ঠিক আসে নি, কারণ আমরা counter ভ্যারিয়েবলটির মান ইনিশিয়ালাইজ করিনি! লুপ নিয়ে পর্বে বারবার বলা হয়েছিল এই ইনিশিয়ালাইজিং-এর গুরুত্ব সম্পর্কে। আমরা এটিকে শূণ্য দিয়ে ইনিশিয়ালাইজ করে ফেলি।

#include <stdio.h>
int main() {
    char str[] = "This is a random string!";
    int i, counter=0;
    for (i=0;str[i] != '\0';i++) {
        counter++;
    }
    printf("There are %d characters in the string!\n", counter);
    return 0;
}

এবার এটি ঠিক মতই আউটপুট দিবে। বিশ্বাস না হলে নিজে হিসেব করে মিলিয়ে দেখ!

এখানে আমরা counter ভ্যারিয়েবলটি ব্যবহার না করলেও পারতাম। কারণ খেয়াল করে দেখ, লুপ শেষে i এবং counter-এর মান কিন্তু একই থাকছে! তাহলে আমরা আমাদের কোডটা আরেকটু পরিবর্তন করে লিখিঃ

#include <stdio.h>
int main() {
    char str[] = "This is a random string!";
    int i;
    for (i=0;str[i] != '\0';i++) {
    }
    printf("There are %d characters in the string!\n", i);
    return 0;
}

এটাকে আমরা আরেকটু সুন্দর করে লিখতে পারতাম এভাবেঃ

#include <stdio.h>
int main() {
    char str[] = "This is a random string!";
    int i=0; // initialize!!
    while (str[i] != '\0') i++;
    printf("There are %d characters in the string!\n", i);
    return 0;
}

দেখ আমি এখানে while-লুপের মধ্যে সেকেন্ড ব্র্যাকেটটা দি নাই। while লুপ কিংবা for লুপ কিংবা if-else ল্যাডার – যখন এর মধ্যে শুধু একটি মাত্র স্টেটমেন্ট (এক্ষেত্রে i++) থাকবে, তখন সেকেন্ড ব্র্যাকেটটা না দিলেও চলবে!

এবার আমরা দু’টি স্ট্রিং জোড়া লাগাবো! প্রথমেই আমরা first name আর second name আলাদা ভাবে ইনপুট নি, এবং পুরো নামের জন্য আরেকটি স্ট্রিং ডিক্লেয়ার করে রাখি।

#include <stdio.h>
int main() {
    char first[20], last[20], full[40];
    scanf("%s %s", first, last);
    return 0;
}

এবার আমাদেরকে যা করতে হবে, তাহল প্রথমে একটি লুপ চালিয়ে ফার্স্ট নেমটাকে ফুল নামের অ্যারেটাতে বসাতে হবে। এরপর একটি স্পেস দিতে হবে। এরপর লাস্ট নেমটাও লুপ চালিয়ে বসিয়ে দিতে হবে। তাহলে কাজটা করে ফেলি! কিন্তু এজন্য আমাদের স্ট্রিং-এর দৈর্ঘ্যও জানতে হবে। আগে আমরা দৈর্ঘ্য বের করে রাখি!

#include <stdio.h>
int main() {
    char first[20], last[20], full[40];
    scanf("%s %s", first, last);
    // doirgho ber kortichi
    int len1=0, len2=0;
    while (first[len1] != '\0') len1++;
    while (last[len2] != '\0') len2++;
    
    return 0;
}

এবার লুপ চালিয়ে কাজটা করে ফেলি!

#include <stdio.h>
int main() {
    char first[20], last[20], full[40];
    scanf("%s %s", first, last);
    // doirgho ber kortichi
    int len1=0, len2=0;
    while (first[len1] != '\0') len1++;
    while (last[len2] != '\0') len2++;
    // first name ta full e boshacchi
    int i;
    for (i=0; i<len1;i++) {
        full[i] = first[i];
    }
    // space dicchi 
    full[i] = ' ';
    i=i+1; // bolo to eta na korle ki hobe? 
    // last name
    
    return 0;
}

আমাদের ফার্স্ট নেম আর স্পেস বসানো শেষ। এবার কাজ লাস্ট নেম নিয়ে! লাস্ট নেমটা full-অ্যারের কত নাম্বার ইনডেক্স থেকে শুরু হবে বল তো? (len1+1-1) ইনডেক্স থেকে! সোজা কথায় len1 ইনডেক্স থেকে। তবে সেটা i ভ্যারিয়েবলের মধ্যে ইতোমধ্যেই আছে কিন্তু! তাই এটা নিয়ে আমাদেরকে মাথা ঘামাতে হবে না! আমরা যা করবো তা হল, লাস্ট নেমের শূণ্য থেকে শুরু করে len2-1 পর্যন্ত ইনডেক্স-এর ক্যারেক্টারগুলো এবার full-এ বসিয়ে দিব। কাজটা আমার কোড দেখার আগে নিজে একবার করার চেষ্টা কর।

খুব সহজ ভাবে কোডট করলে সেটা হবে এমনঃ

#include <stdio.h>
int main() {
    char first[20], last[20], full[40];
    scanf("%s %s", first, last);
    // doirgho ber kortichi
    int len1=0, len2=0;
    while (first[len1] != '\0') len1++;
    while (last[len2] != '\0') len2++;
    // first name ta full e boshacchi
    int i;
    for (i=0; i<len1;i++) {
        full[i] = first[i];
    }
    // space dicchi
    
    full[i] = ' ';
    i=i+1; // bolo to eta na korle ki hobe? 
    // last name
    int j=0;
    for (j=0; j<len2; j++, i++) {
        full[i] = last[j];
    }
    return 0;
}

এবার নামটা প্রিন্ট করে দেখা যাক সব ঠিক আছে কি না!

#include <stdio.h>
int main() {
    char first[20], last[20], full[40];
    scanf("%s %s", first, last);
    // doirgho ber kortichi
    int len1=0, len2=0;
    while (first[len1] != '\0') len1++;
    while (last[len2] != '\0') len2++;
    // first name ta full e boshacchi
    int i;
    for (i=0; i<len1;i++) {
        full[i] = first[i];
    }
    // space dicchi
    full[i] = ' ';
    i = i+1;
    // last name
    int j=0;
    for (j=0; j<len2; j++, i++) {
        full[i] = last[j];
    }
    printf("Full Name : %s\n", full);
    return 0;
}

আউটপুটঃ

Snap 2015-08-06 at 20.40.27

Oops! তার মানে আমরা নাল ক্যারেক্টার দিতে ভুলে গিয়েছি!

কোডটা ঠিক করে নিই ঝটপট।

#include <stdio.h>
int main() {
    char first[20], last[20], full[40];
    scanf("%s %s", first, last);
    // doirgho ber kortichi
    int len1=0, len2=0;
    while (first[len1] != '\0') len1++;
    while (last[len2] != '\0') len2++;
    // first name ta full e boshacchi
    int i;
    for (i=0; i<len1;i++) {
        full[i] = first[i];
    }
    // space dicchi
    full[i] = ' ';
    i = i+1;
    // last name
    int j=0;
    for (j=0; j<len2; j++, i++) {
        full[i] = last[j];
    }
    full[i] = '\0';
    printf("Full Name : %s\n", full);
    return 0;
}

এবার সব ঠিক মতই কাজ করবে!

Snap 2015-08-06 at 20.43.59

আমরা যে কাজগুলো করলাম, এগুলো string.h হেডার ফাইলে আগে থেকেই ডিফাইন করা আছে। তাও আমরা নিজেরা করলাম আরও ভাল মত শেখার জন্য। আগামী পর্বে আমরা এই হেডার ফাইলের আরও কিছু প্রি-ডিফাইনড ফাংশন দেখবো এবং সে কাজগুলো কীভাবে নিজে করা যায়, সে সম্পর্কেও চিন্তা ভাবনা করবো!

আপাতত ফিরে আসি কীভাবে স্পেস সহ ইনপুট নিতে হয়, সে প্রসঙ্গে। কাজটা খুবই সোজা। আমরা লিখবো gets(string_name);

কোড লিখেই দেখে ফেলি!

#include <stdio.h>
int main() {
    char str[20];
    printf("Input please : ");
    gets(str);
    printf("Output : %s\n", str);
    return 0;
}

কোডটি রান করে দেখিঃ

Snap 2015-08-06 at 20.48.25

কাজ শেষ! তবে তুমি যখন scanf() আর gets() একই কোডে ব্যবহার করবা, তখন একটা সমস্যার সম্মুখীন হতে পার। নিচের কোডটা রান করে দেখঃ

#include <stdio.h>
int main() {
    printf("How many sentences do you have?\n");
    int n,i;
    char str[100];
    scanf("%d", &n);
    for (i=1; i<=n;i++) {
        gets(str);
        printf("Input %d = %s\n",i, str);
    }
    return 0;
}

Snap 2015-08-06 at 21.40.46

খেয়াল করে দেখ, এখানে প্রথমে “Input 1” হিসেবে একটি Empty String প্রিন্ট হয়ে যাচ্ছে! কেন এমন হচ্ছে? কারণটা মাথার উপর দিয়ে যাবে। তাও বলে রাখি। কারণ হল 3 লিখে Enter দেওয়ার পর সেটা বাফারে থেকে যায়। এরপর gets() ব্যবহার করলে এটি সেই Enter-টিকেই একটি স্ট্রিং হিসেবে ধরে নেয়! এই সমস্যা সমাধানের উপায় হল, scanf() আর gets() একসাথে ব্যবহার করলে সেক্ষেত্রে scanf()-এর পর বাফারের “Enter”-টিকে ইগনোর করার জন্য একটি getchar() দিয়ে রাখা। দেখ, নিচের কোডটা ঠিক মত কাজ করবেঃ

#include <stdio.h>
int main() {
    printf("How many sentences do you have?\n");
    int n,i;
    char str[100];
    scanf("%d", &n);
    getchar();
    for (i=1; i<=n;i++) {
        gets(str);
        printf("Input %d = %s\n",i, str);
    }
    return 0;
}

Snap 2015-08-06 at 21.46.27

আজ এ পর্যন্তই! কোনো প্রশ্ন থাকলে কমেন্ট সেকশনে করে ফেল!

Muntasir Wahed

Muntasir Wahed

System Administrator at স্বশিক্ষা.com
Jack of all trades, master of none.
Muntasir Wahed
Muntasir Wahed