আপনার ফাংশনের স্বাক্ষর হওয়া দরকার:
const char * myFunction()
{
return "My String";
}
পটভূমি:
এটি সি ও সি ++ এর পক্ষে এতটা মৌলিক, তবে আরও কিছুটা আলোচনা করা উচিত।
সি (& সি ++ বিষয়টির জন্য), একটি স্ট্রিং কেবল একটি শূন্য বাইট দ্বারা সমাপ্ত বাইটের একটি অ্যারে - সুতরাং স্ট্রিংয়ের এই বিশেষ স্বাদকে উপস্থাপন করতে "স্ট্রিং-শূন্য" শব্দটি ব্যবহৃত হয়। অন্যান্য ধরণের স্ট্রিং রয়েছে, তবে সি (& সি ++) এ, এই স্বাদটি ভাষা থেকেই স্বভাবগতভাবে বোঝা যায়। অন্যান্য ভাষা (জাভা, পাস্কাল ইত্যাদি) "আমার স্ট্রিং" বোঝার জন্য বিভিন্ন পদ্ধতি ব্যবহার করে।
আপনি যদি কখনও উইন্ডোজ এপিআই ব্যবহার করেন (যা সি ++ তে থাকে) তবে আপনি বেশ নিয়মিত প্যারামিটারগুলি দেখতে পাবেন যেমন: "এলপিসিএসআরটি এলপিএসএন নাম"। 'Sz' অংশটি 'স্ট্রিং-শূন্য' এর এই ধারণাটি উপস্থাপন করে: নাল (/ শূন্য) টার্মিনেটর সহ বাইটের অ্যারে।
ব্যাখ্যা:
এই 'পরিচয়ের' স্বার্থে, আমি 'বাইটস' এবং 'অক্ষর' শব্দটি পরস্পর বদলে ব্যবহার করি, কারণ এইভাবে শেখা সহজ। সচেতন থাকুন যে আন্তর্জাতিক অক্ষরগুলি মোকাবেলায় অন্যান্য পদ্ধতি (প্রশস্ত অক্ষর এবং মাল্টি-বাইট অক্ষর সিস্টেম ( এমবিসিএস )) রয়েছে। ইউটিএফ -8 একটি এমবিসিএসের উদাহরণ। পরিচয়ের স্বার্থে, আমি এই সমস্ত কিছু নিঃশব্দে 'এড়িয়ে যাই'।
স্মৃতি:
এর অর্থ হল "আমার স্ট্রিং" এর মতো একটি স্ট্রিং আসলে 9 + 1 (= 10!) বাইট ব্যবহার করে। আপনি অবশেষে কখন ডায়নামিকভাবে স্ট্রিং বরাদ্দ করতে পারেন তা জেনে রাখা গুরুত্বপূর্ণ।
সুতরাং, এই 'শূন্যের অবসান' না করে আপনার কোনও স্ট্রিং নেই। আপনার কাছে অক্ষরের একটি অ্যারে রয়েছে (এটি একটি বাফার নামেও পরিচিত) স্মৃতিতে ঘুরে।
তথ্য দীর্ঘায়ু:
ফাংশনটি এভাবে ব্যবহার করুন:
const char * myFunction()
{
return "My String";
}
int main()
{
const char* szSomeString = myFunction(); // Fraught with problems
printf("%s", szSomeString);
}
... সাধারণত আপনাকে এলোমেলোভাবে ব্যতিক্রমহীন-ব্যতিক্রম / বিভাগের ত্রুটিগুলি এবং এর মতো করে বিশেষত 'রাস্তার নিচে' নিয়ে যায়।
সংক্ষেপে, যদিও আমার উত্তরটি সঠিক - 10 এর মধ্যে 9 বার আপনি কোনও প্রোগ্রামটি শেষ করবেন যা আপনি যদি এমনভাবে ব্যবহার করেন তবে ক্র্যাশ হবে, বিশেষত যদি আপনি মনে করেন যে এটি করা ভাল 'অনুশীলন'। সংক্ষেপে: এটি সাধারণত হয় না।
উদাহরণস্বরূপ, ভবিষ্যতে কিছু সময় কল্পনা করুন, স্ট্রিংটি এখন কোনও উপায়ে হেরফের করা দরকার। সাধারণত, একটি কোডার 'সহজ পথ গ্রহণ করবে' এবং (কোড চেষ্টা করে) এই জাতীয় কোড লিখবে:
const char * myFunction(const char* name)
{
char szBuffer[255];
snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
return szBuffer;
}
অর্থাৎ আপনার প্রোগ্রাম কারণ কম্পাইলার (/ নাও হতে পারে হতে পারে) দ্বারা ব্যবহৃত মেমরি মুক্তি বিপর্যস্ত হবে szBuffer
সময় দ্বারা printf()
এ main()
বলা হয়। (আপনার সংকলকটিও আপনাকে আগে থেকেই এ জাতীয় সমস্যা সম্পর্কে সতর্ক করা উচিত))
স্ট্রিংগুলি ফেরত দেওয়ার দুটি উপায় রয়েছে যা এত তাড়াতাড়ি বাধা পাবে না।
- রিটার্নিং বাফার (স্থির বা গতিশীল বরাদ্দ) যা কিছু সময়ের জন্য বেঁচে থাকে। সি ++ তে
std::string
ডেটা-এর দীর্ঘায়ু (যা ফাংশনের রিটার্নের মান পরিবর্তন করতে হবে) পরিচালনা করতে 'সহায়ক ক্লাস' ব্যবহার করুন (উদাহরণস্বরূপ ), বা
- তথ্য সহ পূরণ করা হয় যে ফাংশন একটি বাফার পাস।
মনে রাখবেন যে সি তে পয়েন্টার ব্যবহার না করে স্ট্রিংগুলি ব্যবহার করা অসম্ভব আমি যেমন দেখিয়েছি যে সেগুলি সমার্থক। এমনকি টেমপ্লেট ক্লাস সহ সি ++ তেও সর্বদা পটভূমিতে বাফার (যা পয়েন্টার) ব্যবহৃত হচ্ছে।
সুতরাং, (এখন পরিবর্তিত প্রশ্ন) আরও ভাল উত্তর দিতে। (সরবরাহ করা যেতে পারে এমন বিভিন্ন 'অন্যান্য উত্তর' থাকার নিশ্চয়তা রয়েছে))
নিরাপদ উত্তর:
1 উদাহরণস্বরূপ, স্ট্যাটিকালি বরাদ্দ স্ট্রিংগুলি ব্যবহার করে:
const char* calculateMonth(int month)
{
static char* months[] = {"Jan", "Feb", "Mar" .... };
static char badFood[] = "Unknown";
if (month<1 || month>12)
return badFood; // Choose whatever is appropriate for bad input. Crashing is never appropriate however.
else
return months[month-1];
}
int main()
{
printf("%s", calculateMonth(2)); // Prints "Feb"
}
এখানে 'স্ট্যাটিক' কী করে (অনেক প্রোগ্রামার এই ধরণের 'বরাদ্দ' পছন্দ করেন না) তা হ'ল স্ট্রিংগুলি প্রোগ্রামের ডেটা বিভাগে রাখে। এটি স্থায়ীভাবে বরাদ্দ।
আপনি যদি সি ++ এ যান তবে আপনি একই কৌশল ব্যবহার করবেন:
class Foo
{
char _someData[12];
public:
const char* someFunction() const
{ // The final 'const' is to let the compiler know that nothing is changed in the class when this function is called.
return _someData;
}
}
... তবে সহায়ক ক্লাসগুলি ব্যবহার করা সম্ভবত এটি সহজতর, যেমন std::string
আপনি যদি নিজের ব্যবহারের জন্য কোডটি লিখে থাকেন (এবং অন্যের সাথে ভাগ করে নেওয়ার জন্য কোনও লাইব্রেরির অংশ নয়)।
উদাহরণ 2, কলার-সংজ্ঞায়িত বাফার ব্যবহার করে:
চারপাশে স্ট্রিংগুলি পাস করার এটি আরও 'বোকা' way ফিরিয়ে দেওয়া ডেটা কলিং পার্টির কারসাজির বিষয় নয়। এটি হ'ল উদাহরণ 1 সহজেই একটি কলিং পার্টির দ্বারা আপত্তিজনকভাবে ব্যবহার করা যায় এবং আপনাকে অ্যাপ্লিকেশন ত্রুটিতে প্রকাশ করতে পারে। এইভাবে, এটি অনেক বেশি নিরাপদ (যদিও কোডের আরও লাইন ব্যবহার করে):
void calculateMonth(int month, char* pszMonth, int buffersize)
{
const char* months[] = {"Jan", "Feb", "Mar" .... }; // Allocated dynamically during the function call. (Can be inefficient with a bad compiler)
if (!pszMonth || buffersize<1)
return; // Bad input. Let junk deal with junk data.
if (month<1 || month>12)
{
*pszMonth = '\0'; // Return an 'empty' string
// OR: strncpy(pszMonth, "Bad Month", buffersize-1);
}
else
{
strncpy(pszMonth, months[month-1], buffersize-1);
}
pszMonth[buffersize-1] = '\0'; // Ensure a valid terminating zero! Many people forget this!
}
int main()
{
char month[16]; // 16 bytes allocated here on the stack.
calculateMonth(3, month, sizeof(month));
printf("%s", month); // Prints "Mar"
}
দ্বিতীয় পদ্ধতিটি আরও ভাল হওয়ার কারণগুলির অনেকগুলি কারণ রয়েছে, বিশেষত যদি আপনি অন্যের দ্বারা ব্যবহারের জন্য কোনও গ্রন্থাগার লেখেন (আপনার কোনও নির্দিষ্ট বরাদ্দ / অবলম্বন প্রকল্পে লক করা দরকার না, তৃতীয় পক্ষগুলি আপনার কোডটি ভঙ্গ করতে পারে না, এবং আপনাকে একটি নির্দিষ্ট মেমরি পরিচালনা গ্রন্থাগারের সাথে লিঙ্ক করার দরকার নেই), তবে সমস্ত কোডের মতো, আপনি কী পছন্দ করেন তা এটি আপনার উপর নির্ভর করে। সে কারণে, বেশিরভাগ লোক উদাহরণ 1 বেছে নিয়েছে যতক্ষণ না তারা এত বার পোড়া হয়ে গেছে যে তারা এভাবে আর লিখতে অস্বীকার করে;)
দাবি পরিত্যাগী:
আমি বেশ কয়েক বছর আগে অবসর নিয়েছিলাম এবং আমার সি এখন কিছুটা মরিচা। এই ডেমো কোডটি সমস্ত সি দিয়ে সঠিকভাবে সংকলন করা উচিত (যদিও এটি কোনও সি ++ কম্পাইলারের জন্য ঠিক আছে)।