c - অক্ষর অ্যারেগুলি স্ট্রিং হিসাবে কীভাবে ব্যবহার করা উচিত?




string c-strings (3)

আমি বুঝতে পারি যে সি তে স্ট্রিংগুলি কেবল চরিত্রের অ্যারে। সুতরাং আমি নিম্নলিখিত কোডটি চেষ্টা করেছিলাম, তবে এটি অদ্ভুত ফলাফল দেয় যেমন জঞ্জাল আউটপুট বা প্রোগ্রাম ক্র্যাশগুলি:

#include <stdio.h>

int main (void)
{
  char str [5] = "hello";
  puts(str);
}

কেন এই কাজ করে না?

এটি gcc -std=c17 -pedantic-errors -Wall -Wextra দিয়ে পরিষ্কারভাবে সংকলন করে।

দ্রষ্টব্য: এই পোস্টটি কোনও স্ট্রিং ঘোষণার সময় NUL টার্মিনেটরের জন্য ঘর বরাদ্দ করতে ব্যর্থতা থেকে উদ্ভূত সমস্যাগুলির জন্য ক্যানোনিকাল এফএকিউ হিসাবে ব্যবহৃত হতে বোঝানো হয়েছিল।


Intuitively ...

একটি ভেরিয়েবল (জিনিসগুলি ধারণ করে) এবং একটি স্ট্রিংকে একটি ভেরিয়েবল হিসাবে বিবেচনা করুন (ভেরিয়েবলের মধ্যে স্থাপন করা যেতে পারে)।

তারা অবশ্যই একই জিনিস নয়। আপনার ক্ষেত্রে ভেরিয়েবলটি স্ট্রিং ধরে রাখতে খুব ছোট, তাই স্ট্রিংটি কেটে যায়। (সি এর "উদ্ধৃতিযুক্ত স্ট্রিং" এর শেষে একটি নিখুঁত নাল অক্ষর রয়েছে))

তবে স্ট্রিংয়ের চেয়ে অনেক বড় অ্যারেতে একটি স্ট্রিং সঞ্চয় করা সম্ভব।

নোট করুন যে সাধারণ অ্যাসাইনমেন্ট এবং তুলনা অপারেটরগুলি ( = == < ইত্যাদি) আপনার প্রত্যাশার মতো কাজ করে না। তবে ক্রিয়াকলাপগুলির strxyz পরিবারটি খুব কাছাকাছি চলে আসবে, আপনি যখন জানবেন আপনি কী করছেন। strings এবং arrays


সমস্ত স্ট্রিংগুলিকে একটি অক্ষরের অ্যারে হিসাবে বিবেচনা করা যেতে পারে ( হ্যাঁ ), সমস্ত চরিত্রের অ্যারেগুলি স্ট্রিং ( না ) হিসাবে বিবেচনা করা যেতে পারে?

কেন না? এবং কেন এটি গুরুত্বপূর্ণ?

স্ট্রিংয়ের অংশ হিসাবে স্ট্রিংয়ের দৈর্ঘ্য কোথাও সংরক্ষণ করা হয়নি এবং স্ট্রিং সংজ্ঞায়িত এমন স্ট্যান্ডার্ডের রেফারেন্সের পাশাপাশি অন্যান্য উত্তরগুলির পাশাপাশি, ফ্লিপ-সাইডটি "সি লাইব্রেরি ফাংশনগুলি স্ট্রিংগুলি কীভাবে পরিচালনা করবে?"

যখন কোনও অক্ষর অ্যারে একই অক্ষর ধারণ করতে পারে তবে এটি কেবল অক্ষরের একটি অ্যারে না হলে শেষ বর্ণটি নুল-টার্মিনেটিং অক্ষর অনুসরণ না করে followed সেই নুল-টার্মিনেটিং চরিত্রটি হ'ল অক্ষরের অ্যারেটিকে স্ট্রিং হিসাবে বিবেচনা করতে (হিসাবে পরিচালনা করা) অনুমতি দেয়।

সি এর সমস্ত ফাংশন যা আর্গুমেন্ট হিসাবে একটি স্ট্রিং প্রত্যাশা করে অক্ষরের ক্রমটি বাতিল-সমাপ্ত হওয়ার প্রত্যাশা করে। কেন?

এটি সমস্ত স্ট্রিং ফাংশনগুলি যেভাবে কাজ করে তা করতে হবে। যেহেতু দৈর্ঘ্য একটি অ্যারের অংশ হিসাবে অন্তর্ভুক্ত করা হয়নি, স্ট্রিং-ফাংশন, নুল-চরিত্রের (যেমন '\0' - দশমিক 0 সমান) পাওয়া না পাওয়া পর্যন্ত অ্যারেতে স্ক্যান করে এগিয়ে যান। ASCII সারণী এবং বিবরণ দেখুন । আপনি strcpy , strchr , strcspn ইত্যাদি ব্যবহার করছেন কিনা তা বিবেচনা না strchr All সমস্ত স্ট্রিং ফাংশন সেই স্ট্রিংয়ের শেষ কোথায় রয়েছে তা নির্ধারণের জন্য উপস্থিত নুল-টার্মিনেটিং চরিত্রের উপর নির্ভর করে।

string.h থেকে দুটি অনুরূপ ফাংশনের তুলনা নুল-সমাপ্তি চরিত্রের গুরুত্বকে জোর দেবে। উদাহরণস্বরূপ নিন:

    char *strcpy(char *dest, const char *src);

strcpy ফাংশনটি কেবল এনআরসি-টার্মিনেটিং চরিত্র না পাওয়া পর্যন্ত src থেকে dest বাইটগুলি অনুলিপি করে যেখানে অক্ষরগুলি অনুলিপি করা বন্ধ করতে হবে তা বলছে strcpy এখন অনুরূপ ফাংশন memcpy :

    void *memcpy(void *dest, const void *src, size_t n);

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

(যা স্ট্রাইকটির (বা কোনও স্ট্রিংয়ের প্রত্যাশা করা কোনও ফাংশন) কী strcpy পারে তার উপর জোর দেয় - যদি আপনি ফাংশনটি নুল-টার্মিনেটেড স্ট্রিং সরবরাহ করতে ব্যর্থ হন - কোথায় থামবেন তা কোনও ধারণা নেই এবং আপনার বাকি স্মৃতিতে আনন্দের সাথে ছুটে যাবে it কোনও শূণ্য চরিত্র সবেমাত্র মেমরির কোথাও খুঁজে পাওয়া যায় না - বা কোনও সেগমেন্টেশন ফল্ট ঘটে) অবধি সংজ্ঞায়িত আচরণের অনুরোধ করা বিভাগটি)

কারণেই নুল-টার্মিনেটেড স্ট্রিংয়ের প্রত্যাশী ক্রিয়াকলাপগুলি অবশ্যই নুল-সমাপ্ত স্ট্রিংটি পাস করতে হবে এবং কেন এটি গুরুত্বপূর্ণ why


এসি স্ট্রিং একটি ক্যারেক্টার অ্যারে যা নাল টার্মিনেটর দিয়ে শেষ হয়।

সমস্ত অক্ষরের একটি সারণী মান আছে। নাল টার্মিনেটর হল প্রতীক মান 0 (শূন্য)। এটি একটি স্ট্রিংয়ের শেষ চিহ্নিত করতে ব্যবহৃত হয়। স্ট্রিংয়ের আকার কোথাও সংরক্ষণ করা হয়নি বলে এটি প্রয়োজনীয়।

অতএব, আপনি যখনই কোনও স্ট্রিংয়ের জন্য ঘর বরাদ্দ করবেন তখন নাল টার্মিনেটর চরিত্রের জন্য আপনার অবশ্যই পর্যাপ্ত জায়গা অন্তর্ভুক্ত করতে হবে। আপনার উদাহরণ এটি করে না, এটি কেবলমাত্র "hello" এর 5 টি অক্ষরের জন্য ঘর বরাদ্দ করে। সঠিক কোডটি হওয়া উচিত:

char str[6] = "hello";

বা সমতুল্যভাবে, আপনি 5 টি অক্ষরের সাথে 1 টি নাল টার্মিনেটরের জন্য স্ব-ডকুমেন্টিং কোড লিখতে পারেন:

char str[5+1] = "hello";

রান-টাইমে স্ট্রিংয়ের জন্য গতিশীলভাবে মেমরি বরাদ্দ করার সময়, আপনাকে নাল টার্মিনেটরের জন্য ঘরও বরাদ্দ করতে হবে:

char input[n] = ... ;
...
char* str = malloc(strlen(input) + 1);

যদি আপনি কোনও স্ট্রিং শেষে নাল টার্মিনেটর সংযোজন করেন না, তবে স্ট্রিংয়ের প্রত্যাশিত লাইব্রেরি ফাংশনগুলি সঠিকভাবে কাজ করবে না এবং আপনি "অপরিজ্ঞাত আচরণ" বাগগুলি পাবেন যেমন জঞ্জাল আউটপুট বা প্রোগ্রাম ক্র্যাশ।

সিতে নাল টার্মিনেটর চরিত্রটি লেখার সর্বাধিক সাধারণ উপায় হ'ল তথাকথিত "অক্টাল এস্কেপ সিকোয়েন্স" ব্যবহার করে, এটির মতো দেখাচ্ছে: '\0' । এটি 0 লেখার 100% সমতুল্য, তবে state স্ব-ডকুমেন্টিং কোড হিসাবে পরিবেশন করে যে শূন্যটি স্পষ্টভাবে নাল টার্মিনেটর হিসাবে বোঝানো হয়েছে। কোড যেমন if(str[i] == '\0') নির্দিষ্ট অক্ষরটি নাল টার্মিনেটর কিনা তা পরীক্ষা করবে।

দয়া করে মনে রাখবেন নাল টার্মিনেটর শব্দটির নাল পয়েন্টার বা NULL ম্যাক্রোর সাথে কোনও সম্পর্ক নেই! এটি বিভ্রান্তিকর হতে পারে - খুব অনুরূপ নাম তবে খুব আলাদা অর্থ। এ কারণেই নাল টার্মিনেটরটিকে কখনও কখনও এক এল এর সাথে NULL হিসাবে উল্লেখ করা হয়, NULL বা নাল পয়েন্টারগুলির সাথে বিভ্রান্ত হওয়ার দরকার নেই। আরও তথ্যের জন্য এই এসও প্রশ্নের উত্তর দেখুন।

আপনার কোডের "hello" কে স্ট্রিং আক্ষরিক বলা হয়। এটি কেবল পঠনযোগ্য স্ট্রিং হিসাবে বিবেচিত হবে। সিনট্যাক্সের অর্থ হল যে সংকলকটি স্বয়ংক্রিয়ভাবে স্ট্রিংয়ের শেষে একটি নাল টার্মিনেটর সংযোজন করবে। সুতরাং আপনি যদি sizeof("hello") মুদ্রণ করেন তবে আপনি 5 টি পাবেন না, কারণ আপনি নাল টার্মিনেটর সহ অ্যারের আকার পাবেন।

এটি জিসিসি দিয়ে পরিষ্কারভাবে সংকলন করে

প্রকৃতপক্ষে, একটি সতর্কতাও নয়। এটি সি ভাষার এমন একটি সূক্ষ্ম বিশদ / ত্রুটির কারণে যা অক্ষরের অ্যারেগুলিকে একটি স্ট্রিং আক্ষরিক দিয়ে আরম্ভ করতে দেয় যা অ্যারেতে জায়গা রয়েছে ঠিক তেমন অক্ষর ধারণ করে এবং নীরবে নাল টার্মিনেটর বাতিল করে দেয় (C17 6.7.9 / 15)। ভাষাটি ইচ্ছাকৃতভাবে historical তিহাসিক কারণে এই জাতীয় আচরণ করছে, বিশদগুলির জন্য স্ট্রিং ইনিশিয়ালাইজেশনের জন্য বেমানান জিসিসি ডায়াগোনস্টিক দেখুন। এছাড়াও নোট করুন যে সি ++ এখানে আলাদা এবং এই কৌশল / ত্রুটি ব্যবহার করার অনুমতি দেয় না।






nul