आपका फ़ंक्शन हस्ताक्षर होना चाहिए:
const char * myFunction()
{
return "My String";
}
पृष्ठभूमि:
यह C & C ++ के लिए बहुत मौलिक है, लेकिन थोड़ी और चर्चा क्रम में होनी चाहिए।
C (& C ++ में उस मामले के लिए), एक स्ट्रिंग बाइट्स की एक सरणी है जिसे एक शून्य बाइट के साथ समाप्त किया जाता है - इसलिए स्ट्रिंग के इस विशेष स्वाद का प्रतिनिधित्व करने के लिए "स्ट्रिंग-शून्य" शब्द का उपयोग किया जाता है। अन्य प्रकार के तार हैं, लेकिन सी (और सी ++) में, यह स्वाद स्वाभाविक रूप से भाषा द्वारा ही समझा जाता है। अन्य भाषाएँ (जावा, पास्कल, आदि) "मेरी स्ट्रिंग" को समझने के लिए विभिन्न तरीकों का उपयोग करती हैं।
यदि आप कभी भी Windows API (जो C ++ में है) का उपयोग करते हैं, तो आपको नियमित रूप से फ़ंक्शन पैरामीटर जैसे: "LPCSTR lpszNot" दिखाई देंगे। 'Sz' भाग 'string-शून्य' की इस धारणा को दर्शाता है: एक शून्य (/ शून्य) टर्मिनेटर के साथ बाइट्स की एक सरणी।
स्पष्टीकरण:
इस 'परिचय' के लिए, मैं 'बाइट्स' और 'अक्षर' शब्द का परस्पर उपयोग करता हूं, क्योंकि इस तरह से सीखना आसान है। विदित हो कि अन्य विधियाँ (विस्तृत-वर्ण और बहु-बाइट वर्ण प्रणालियाँ ( mbcs )) हैं जिनका उपयोग अंतर्राष्ट्रीय वर्णों का सामना करने के लिए किया जाता है। UTF-8 एक mbcs का एक उदाहरण है। इंट्रो के लिए, मैं चुपचाप इस सब को 'स्किप ओवर' करता हूं।
स्मृति:
इसका मतलब है कि "मेरी स्ट्रिंग" जैसी एक स्ट्रिंग वास्तव में 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()
कहा जाता है। (आपके कंपाइलर को भी आपको ऐसी समस्याओं से पहले ही आगाह कर देना चाहिए।)
स्ट्रिंग्स को वापस करने के दो तरीके हैं जो इतनी आसानी से बारफ नहीं करेंगे।
- लौटने वाले बफ़र्स (स्थिर या गतिशील रूप से आवंटित) जो थोड़ी देर के लिए रहते हैं। C ++
std::string
में डेटा की लंबी उम्र को संभालने के लिए 'हेल्पर क्लासेस' (उदाहरण के लिए ) का उपयोग करें (जिसमें फ़ंक्शन के रिटर्न मान को बदलने की आवश्यकता होती है, या या
- फ़ंक्शन के लिए एक बफ़र पास करें जो जानकारी से भर जाता है।
ध्यान दें कि सी में पॉइंटर्स का उपयोग किए बिना स्ट्रिंग्स का उपयोग करना असंभव है जैसा कि मैंने दिखाया है, वे समानार्थक हैं। यहां तक कि टेम्पलेट कक्षाओं के साथ C ++ में, पृष्ठभूमि में हमेशा बफ़र (यानी, पॉइंटर्स) का उपयोग किया जा रहा है।
इसलिए, (अब संशोधित प्रश्न) का बेहतर उत्तर देने के लिए। (निश्चित रूप से 'अन्य उत्तर' प्रदान किए जा सकते हैं।)
सुरक्षित उत्तर:
उदाहरण 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"
}
यहां 'स्थिर' क्या करता है (कई प्रोग्रामर इस तरह के 'आवंटन' को पसंद नहीं करते हैं) यह है कि स्ट्रिंग्स को प्रोग्राम के डेटा सेगमेंट में डाल दिया जाता है। यही है, यह स्थायी रूप से आवंटित किया गया है।
यदि आप C ++ से आगे बढ़ते हैं, तो आप समान रणनीतियों का उपयोग करेंगे:
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, कॉलर-परिभाषित बफ़र्स का उपयोग कर:
यह चारों ओर तार गुजरने का अधिक 'मूर्खतापूर्ण' तरीका है। लौटाया गया डेटा कॉलिंग पार्टी द्वारा हेरफेर के अधीन नहीं है। यही है, उदाहरण 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 का चयन करते हैं जब तक कि उन्हें इतनी बार जलाया नहीं गया है कि वे इसे इस तरह से लिखने से इनकार करते हैं;)
अस्वीकरण:
मैंने कई साल पहले संन्यास लिया था और मेरा सी अब थोड़ा रस्टी है। यह डेमो कोड सभी को C के साथ ठीक से संकलित करना चाहिए (यह किसी भी C ++ कंपाइलर के लिए ठीक है)।