सी में एक स्ट्रिंग शाब्दिक का "जीवन-समय"


84

क्या सूचक निम्न फ़ंक्शन द्वारा लौटाया नहीं जा सकेगा?

char *foo(int rc)
{
    switch (rc)
    {
        case 1:

            return("one");

        case 2:

            return("two");

        default:

            return("whatever");
    }
}

तो C / C ++ में एक स्थानीय चर का जीवनकाल व्यावहारिक रूप से केवल कार्य के भीतर ही है, है ना? जिसका अर्थ है, char* foo(int)समाप्त होने के बाद , सूचक इसे वापस नहीं देता है इसका मतलब कुछ भी नहीं है, है ना?

मैं एक स्थानीय चर के जीवनकाल के बारे में थोड़ा भ्रमित हूं। एक अच्छा स्पष्टीकरण क्या है?


10
आपके फ़ंक्शन में एकमात्र "var" पैरामीटर है int rc। इसका जीवनकाल प्रत्येक में से एक पर समाप्त होता है return। जिन बिंदुओं पर आप लौट रहे हैं वे स्ट्रिंग शाब्दिक हैं। स्ट्रिंग के शाब्दिक में स्थिर भंडारण अवधि होती है: उनका जीवनकाल कम से कम कार्यक्रम के अनुसार होता है।
काज

14
@PedroAlves क्यों नहीं? तरीके अमूर्तता की अनुमति देते हैं; क्या होगा अगर भविष्य में स्ट्रिंग को अनुवाद संसाधन से पढ़ा जाएगा, लेकिन किसी उत्पाद के V1 (या V0.5) के लिए अंतर्राष्ट्रीयकरण समर्थन की आवश्यकता नहीं है?
dlev

1
@PedroAlves "आपका कोड निश्चित रूप से काम करेगा (और यदि आप इसे संकलित करने का प्रयास करते हैं तो आप इसे देख सकते हैं)," जिसका पालन ​​नहीं होता है। कई (सबसे? अनिवार्य रूप से हर?) सी संकलक अवैध कोड का उपभोग करेगा, और अक्सर काम करने के लिए प्रकट होने वाले कोड का उत्सर्जन करता है। लेकिन इसे दूसरे कंपाइलर (या एक ही कंपाइलर का एक अलग संस्करण) में आज़माएँ और यह गिर सकता है।
dmckee --- पूर्व-मध्यस्थ ने

6
@PedroAlves, एक ऐसा फ़ंक्शन जो एक एकल स्थिर स्ट्रिंग लौटाता है, वह सीमित उपयोग का हो सकता है, लेकिन इनपुट या ऑब्जेक्ट स्थिति के आधार पर किसी भी एक निरंतर स्ट्रिंग के कितने रिटर्न देता है? एक सरल उदाहरण एक एन्यूमरेशन को अपने स्ट्रिंग प्रतिनिधित्व में बदलने के लिए एक फ़ंक्शन होगा।
मार्क रैनसम

4
आपने strerrorफ़ंक्शन कभी नहीं देखा है , जाहिर है।
काज

जवाबों:


86

हां, एक स्थानीय चर का जीवनकाल उस दायरे ( {, }) के भीतर होता है , जिसमें यह बनाया गया है।

स्थानीय चर में स्वचालित या स्थानीय भंडारण होता है। स्वचालित क्योंकि वे स्वचालित रूप से नष्ट हो जाते हैं एक बार गुंजाइश जिसके भीतर उन्हें बनाया जाता है समाप्त होता है।

हालांकि, आपके पास यहां क्या है एक स्ट्रिंग शाब्दिक है, जिसे एक कार्यान्वयन परिभाषित रीड-ओनली मेमोरी में आवंटित किया गया है। स्ट्रिंग शाब्दिक स्थानीय चर से भिन्न होते हैं और वे जीवन भर कार्यक्रम में जीवित रहते हैं। उनके पास स्थिर अवधि [Ref 1] जीवनकाल है।

चेतावनी!

हालांकि, ध्यान दें कि एक स्ट्रिंग शाब्दिक की सामग्री को संशोधित करने का कोई भी प्रयास एक अपरिभाषित व्यवहार (यूबी) है। उपयोगकर्ता कार्यक्रमों को एक स्ट्रिंग शाब्दिक की सामग्री को संशोधित करने की अनुमति नहीं है।
इसलिए, इसे हमेशा constस्ट्रिंग शाब्दिक घोषित करते समय उपयोग करने के लिए प्रोत्साहित किया जाता है ।

const char*p = "string"; 

के बजाय,

char*p = "string";    

वास्तव में, C ++ में यह बिना स्ट्रिंग स्ट्रिंग को शाब्दिक घोषित करने के लिए दर्शाया constगया है। हालांकि, एक स्ट्रिंग शाब्दिक की घोषणा करने से constआपको एक फायदा मिलता है कि कंपाइलर आमतौर पर आपको एक चेतावनी देगा यदि आप स्ट्रिंग स्ट्रिंग को संशोधित करने का प्रयास करते हैं। दूसरा मामला।

नमूना कार्यक्रम :

#include<string.h> 
int main() 
{ 
    char *str1 = "string Literal"; 
    const char *str2 = "string Literal"; 
    char source[]="Sample string"; 
 
    strcpy(str1,source);    // No warning or error just Uundefined Behavior 
    strcpy(str2,source);    // Compiler issues a warning 
 
    return 0; 
} 

आउटपुट:

cc1: चेतावनियों को त्रुटियों के रूप में व्यवहार किया जा रहा है
prog.c: फ़ंक्शन में 'main':
prog.c: 9: error: 'strcpy' के तर्क 1 को पॉइंटर टार्गेट से क्वालीफायर से हटाता है

सूचना संकलक दूसरे मामले के लिए चेतावनी देता है, लेकिन पहले के लिए नहीं।


यहां कुछ उपयोगकर्ताओं द्वारा पूछे जा रहे प्रश्न का उत्तर देने के लिए:

अभिन्न शाब्दिकों के साथ क्या व्यवहार है?

दूसरे शब्दों में, निम्नलिखित कोड मान्य है?

int *foo()
{
    return &(2);
} 

जवाब है, यह कोड मान्य नहीं है। यह बीमार है और संकलक त्रुटि देगा।

कुछ इस तरह:

prog.c:3: error: lvalue required as unary ‘&’ operand
     

स्ट्रिंग शाब्दिक एल-मान हैं, अर्थात: आप एक स्ट्रिंग शाब्दिक का पता ले सकते हैं, लेकिन इसकी सामग्री को बदल नहीं सकते हैं।
हालांकि, कोई भी अन्य शाब्दिक ( intऔर float, charआदि) आर-मान हैं (सी मानक इन के लिए एक अभिव्यक्ति के मूल्य शब्द का उपयोग करता है ) और उनका पता बिल्कुल नहीं लिया जा सकता है।


[Ref 1] C99 मानक 6.4.5 / 5 "स्ट्रिंग लिटरल्स - शब्दार्थ":

अनुवाद चरण 7 में, एक बाइट या मान शून्य का कोड प्रत्येक मल्टीबीट चरित्र अनुक्रम से जुड़ा होता है जो एक स्ट्रिंग शाब्दिक या शाब्दिक परिणाम होता है। मल्टीबाइट कैरेक्टर सीक्वेंस का उपयोग तब स्टैटिक स्टोरेज की अवधि और लंबाई को शुरू करने के लिए किया जाता है । चरित्र स्ट्रिंग शाब्दिकों के लिए, सरणी तत्वों में चार वर्ण होते हैं, और मल्टीबाइट चरित्र अनुक्रम के अलग-अलग बाइट्स के साथ आरंभिक होते हैं; विस्तृत स्ट्रिंग शाब्दिकों के लिए, सरणी तत्वों में wchar_t टाइप होता है, और उन्हें विस्तृत वर्णों के अनुक्रम के साथ आरंभ किया जाता है ...

यह अनिर्दिष्ट है कि क्या ये सरणियाँ विशिष्ट हैं बशर्ते कि उनके तत्वों में उचित मूल्य हों। यदि प्रोग्राम ऐसे सरणी को संशोधित करने का प्रयास करता है, तो व्यवहार अपरिभाषित है


क्या होगा अगर उपयोगकर्ता कुछ इस तरह से लौट रहा है। char * a = & "abc"; एक वापसी; क्या यह मान्य नहीं होगा?
आश्विन

@ अश्विन: स्ट्रिंग शाब्दिक का प्रकार है char (*)[4]। ऐसा इसलिए है, क्योंकि "एबीसी" का प्रकार है char[4]और सूचक को 4 वर्णों की एक सरणी के रूप में घोषित किया गया है char (*)[4], इसलिए यदि आपको इसका पता लगाने की आवश्यकता है, तो आपको इसे करने की आवश्यकता है char (*a)[4] = &"abc";और हां, यह मान्य है।
आलोक सेव

@ एल्स "एबीसी" है char[4]। (के कारण '\0')
asaelr

1
शायद यह भी एक अच्छा विचार चेतावनी देने के लिए है कि हो सकता है char const s[] = "text";करता नहीं कर sएक चरित्र शाब्दिक है, और इसलिए s होगा , गुंजाइश के अंत में नष्ट हो तो यह करने के लिए कोई जीवित संकेत लटकना होगा।
celtschk

1
@celtschk: मुझे अच्छा लगेगा, लेकिन क्यू विशेष रूप से स्ट्रिंग शाब्दिक के बारे में है, इसलिए मैं इस विषय को हाथ में ले जाऊंगा। फिर भी, मेरे जवाब के लिए यहां रुचि रखने वाले लोगों के लिए, [a] = "string" और char के बीच क्या अंतर है * पी = "स्ट्रिंग"? बल्कि मददगार होना चाहिए।
आलोक सेव 14

74

यह मान्य है। स्ट्रिंग शाब्दिक में स्थिर भंडारण अवधि होती है, इसलिए सूचक झूलता नहीं है।

C के लिए, यह खंड 6.4.5, पैरा 6 में अनिवार्य है:

अनुवाद चरण 7 में, एक बाइट या मान शून्य का कोड प्रत्येक मल्टीबीट चरित्र अनुक्रम से जुड़ा होता है जो एक स्ट्रिंग शाब्दिक या शाब्दिक परिणाम होता है। मल्टीबाइट कैरेक्टर सीक्वेंस का उपयोग तब स्टैटिक स्टोरेज की अवधि और लंबाई को शुरू करने के लिए किया जाता है

और धारा +14.5 में C ++ के लिए, पैराग्राफ 8-11:

8 साधारण स्ट्रिंग शाब्दिक और UTF-8 स्ट्रिंग शाब्दिक को संकीर्ण स्ट्रिंग शाब्दिक के रूप में भी जाना जाता है। एक संकीर्ण स्ट्रिंग शाब्दिक प्रकार "n की सरणी const char" है, जहां n स्ट्रिंग के आकार के रूप में नीचे परिभाषित किया गया है, और इसमें स्थिर भंडारण अवधि (3.7) है।

9 एक स्ट्रिंग शाब्दिक जो यू के साथ शुरू होता है, जैसे कि u"asdf", एक char16_tस्ट्रिंग शाब्दिक है। एक char16_tस्ट्रिंग शाब्दिक प्रकार "n की सरणी const char16_t" है, जहां n स्ट्रिंग का आकार नीचे परिभाषित किया गया है; इसमें स्थिर भंडारण अवधि है और इसे दिए गए वर्णों के साथ आरंभ किया गया है। एक एकल सी-चार char16_tसरोगेट जोड़े के रूप में एक से अधिक चरित्र का निर्माण कर सकता है ।

10 एक स्ट्रिंग शाब्दिक जो यू के साथ शुरू होता है, जैसे कि U"asdf", एक char32_tस्ट्रिंग शाब्दिक है। एक char32_tस्ट्रिंग शाब्दिक प्रकार "n की सरणी const char32_t" है, जहां n स्ट्रिंग का आकार नीचे परिभाषित किया गया है; इसमें स्थिर भंडारण अवधि है और इसे दिए गए वर्णों के साथ आरंभ किया गया है।

11 एक स्ट्रिंग शाब्दिक जो L से शुरू होता है, जैसे कि L"asdf", एक विस्तृत स्ट्रिंग शाब्दिक है। एक विस्तृत स्ट्रिंग शाब्दिक प्रकार "n की सरणी const wchar_t" है, जहां n नीचे स्ट्रिंग के आकार के रूप में परिभाषित किया गया है; इसमें स्थिर भंडारण अवधि है और इसे दिए गए वर्णों के साथ आरंभ किया गया है।


FYI करें: इस जवाब को stackoverflow.com/questions/16470959/…
Shog9

14

स्ट्रिंग शाब्दिक पूरे कार्यक्रम के लिए मान्य हैं (और स्टैक नहीं आवंटित किए गए हैं), इसलिए यह मान्य होगा।

इसके अलावा, स्ट्रिंग शाब्दिक केवल पढ़ने के लिए कर रहे हैं, तो (अच्छा शैली के लिए) हो सकता है आप बदलना चाहिए fooकरने के लिएconst char *foo(int)


क्या होगा अगर उपयोगकर्ता कुछ इस तरह से लौट रहा है। char * a = & "abc"; एक वापसी; क्या यह मान्य नहीं होगा?
आश्विन

&"abc"नहीं है char*। यह सरणी का एक पता है, और इसका प्रकार है char(*)[4]। हालांकि, या तो return &"abc";और char *a="abc";return a;मान्य हैं।
asaelr

@asaelr: वास्तव में, यह केवल एक अच्छी शैली के लिए, विवरण के लिए मेरे उत्तर की जांच करने के लिए अधिक है।
आलोक सेव अप

@ एल्स वेल, अगर वह पूरे कार्यक्रम को लिखता है, तो वह बिना लिखे स्ट्रिंग को बदलने से बच सकता है const, और यह पूरी तरह से कानूनी होगा, लेकिन यह खराब शैली है।
asaelr

यदि यह पूरे कार्यक्रम के लिए वैध है, तो हमें इसे मालेक करने की आवश्यकता क्यों है?
टॉमसवीर

7

हां, यह मान्य कोड है, नीचे केस 1 देखें। आप कम से कम इन तरीकों से किसी फ़ंक्शन से C स्ट्रिंग्स को सुरक्षित रूप से वापस कर सकते हैं:

  • const char*एक स्ट्रिंग शाब्दिक के लिए। इसे संशोधित नहीं किया जा सकता है और कॉलर द्वारा मुक्त नहीं किया जाना चाहिए। नीचे बताई गई नि: शुल्क समस्या के कारण, डिफ़ॉल्ट मान लौटाने के उद्देश्य से यह शायद ही कभी उपयोगी है। यह समझ में आ सकता है कि क्या आपको वास्तव में एक फ़ंक्शन पॉइंटर पास करने की आवश्यकता है, इसलिए आपको स्ट्रिंग वापस करने वाले फ़ंक्शन की आवश्यकता है।

  • char*या const char*एक स्थिर चार बफर के लिए। इसे कॉलर द्वारा मुक्त नहीं किया जाना चाहिए। इसे संशोधित किया जा सकता है (या तो फोन करने वाले द्वारा अगर कब्ज नहीं किया जाता है, या फ़ंक्शन इसे वापस कर रहा है), लेकिन इसे वापस करने वाले फ़ंक्शन में आसानी से कई बफ़र्स नहीं हो सकते हैं, इसलिए यह (आसानी से) थ्रेडसेफ़ नहीं है, और कॉलर को आवश्यकता हो सकती है फ़ंक्शन को कॉल करने से पहले दिए गए मान को कॉपी करना।

  • char*एक बफर के साथ आवंटित malloc। इसे संशोधित किया जा सकता है, लेकिन इसे आमतौर पर कॉलर द्वारा स्पष्ट रूप से मुक्त किया जाना चाहिए और ढेर आवंटन उपरि है। strdupइस प्रकार का है।

  • const char*या char*एक बफ़र के लिए, जो फ़ंक्शन के लिए एक तर्क के रूप में पारित किया गया था (लौटे पॉइंटर को तर्क बफर के पहले तत्व को इंगित करने की आवश्यकता नहीं है)। यह कॉल करने के लिए बफर / मेमोरी प्रबंधन की जिम्मेदारी छोड़ देता है। कई मानक स्ट्रिंग फ़ंक्शन इस प्रकार के होते हैं।

एक समस्या यह है कि, इनको एक फ़ंक्शन में मिलाने से जटिलताएं हो सकती हैं। कॉल करने वाले को यह पता होना चाहिए कि उसे लौटे हुए पॉइंटर को कैसे संभालना चाहिए, यह कब तक वैध है, और यदि कॉलर को इसे मुफ्त करना चाहिए, और रनटाइम पर यह निर्धारित करने का कोई (अच्छा) तरीका नहीं है। इसलिए, उदाहरण के लिए, आपके पास एक फ़ंक्शन नहीं है, जो कभी-कभी एक पॉइंटर-आवंटित बफर को एक पॉइंटर लौटाता है जिसे कॉलर को ज़रूरत होती है free, और कभी-कभी स्ट्रिंग पॉरल से डिफ़ॉल्ट मान के लिए एक पॉइंटर, जो कॉलर को नहीं होना चाहिए free


FYI करें: इस जवाब को stackoverflow.com/questions/16470959/…
Shog9

6

अच्छा प्रश्न। सामान्य तौर पर, आप सही होंगे, लेकिन आपका उदाहरण इसका अपवाद है। संकलक सांख्यिकीय रूप से एक स्ट्रिंग शाब्दिक के लिए वैश्विक स्मृति आवंटित करता है। इसलिए, आपके फ़ंक्शन द्वारा दिया गया पता मान्य है।

यह इतना सी की एक सुविधाजनक सुविधा है, है ना? यह प्रोग्रामर को मैसेज को स्टोर किए जाने वाले मेमोरी के बारे में चिंता करने के लिए प्रोग्रामर को मजबूर किए बिना एक प्रीकंपोज्ड मैसेज को वापस करने की अनुमति देता है।

@ Asaelr का सही अवलोकन पुनः देखें const


: क्या होगा अगर उपयोगकर्ता कुछ इस तरह से लौट रहा है। char * a = & "abc"; एक वापसी; क्या यह मान्य नहीं होगा?
आश्विन

सही। वास्तव में, कोई भी लिख सकता है const char *a = "abc";, छोड़ कर &। कारण यह है कि एक डबल-कोटेड स्ट्रिंग अपने प्रारंभिक चरित्र के पते को हल करता है।
thb

3

स्थानीय चर केवल उस दायरे के भीतर मान्य होते हैं, जो उनके द्वारा घोषित किए गए हैं, हालाँकि आप उस फ़ंक्शन में किसी भी स्थानीय चर को घोषित नहीं करते हैं।

यह एक फ़ंक्शन से स्ट्रिंग शाब्दिक के लिए एक सूचक को वापस करने के लिए पूरी तरह से वैध है, क्योंकि एक स्ट्रिंग शाब्दिक कार्यक्रम के पूरे निष्पादन में मौजूद है, बस staticएक वैश्विक चर के रूप में होगा।

यदि आप इस बारे में चिंता कर रहे हैं कि आप जो कर रहे हैं वह अमान्य नहीं है, तो आपको यह देखने के लिए अपने संकलक चेतावनी को बदल देना चाहिए कि क्या वास्तव में आप कुछ गलत कर रहे हैं।


क्या होगा अगर उपयोगकर्ता कुछ इस तरह से लौट रहा है। char * a = & "abc"; एक वापसी; क्या यह मान्य नहीं होगा?
आश्विन

@ अश्विन: &"abc"प्रकार का नहीं है char*, हालांकि दोनों "abc"और &"abc"कार्यक्रम के पूरे निष्पादन के दौरान मान्य हैं।
3

2

strकभी भी झूलने वाला सूचक नहीं होगा, क्योंकि यह एक स्थिर पते की ओर इशारा करता है जहां स्ट्रिंग शाब्दिक रहते हैं।

यह ज्यादातर होगा केवल पढ़ने के लिए और वैश्विक जब यह लोड किया जाएगा कार्यक्रम के लिए।

यहां तक ​​कि अगर आप मुक्त करने या संशोधित करने का प्रयास करते हैं, तो यह मेमोरी सुरक्षा के साथ प्लेटफार्मों पर एक विभाजन दोष को फेंक देगा ।


FYI करें: इस जवाब को stackoverflow.com/questions/16470959/…
Shog9

अगर यह झूलने वाला नहीं होगा, तो क्या मुझे इसे मलोच करने की जरूरत है? नहीं?
टॉमसवीर

0

स्टैक पर एक स्थानीय चर आवंटित किया जाता है। फ़ंक्शन समाप्त होने के बाद, चर दायरे से बाहर हो जाता है और अब कोड में पहुंच योग्य नहीं है। हालाँकि, यदि आपके पास एक वैश्विक (या बस - अभी तक दायरे से बाहर नहीं है) सूचक है जिसे आपने उस चर को इंगित करने के लिए असाइन किया है, तो यह उस स्थान पर इंगित करेगा जहाँ वह चर था। यह किसी अन्य फ़ंक्शन द्वारा उपयोग किया जाने वाला मान, या अर्थहीन मान हो सकता है।


क्या होगा अगर उपयोगकर्ता कुछ इस तरह से लौट रहा है। char * a = & "abc"; एक वापसी; क्या यह मान्य नहीं होगा?
आश्विन

0

आपके द्वारा दिखाए गए उपरोक्त उदाहरण में, आप वास्तव में आवंटित फ़ंक्शन को वापस कर रहे हैं जो भी फ़ंक्शन करता है जो उपरोक्त कहता है। इसलिए यह स्थानीय सूचक नहीं बनेगा। और इसके अलावा, जिन बिंदुओं को वापस करने की आवश्यकता होती है, उनके लिए वैश्विक खंड में मेमोरी आवंटित की जाती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.