const char * const बनाम कास्ट char *?


110

मैं कुछ उदाहरण कार्यक्रमों के माध्यम से अपने आप को C ++ से परिचित करने के लिए दौड़ रहा हूं और मैंने निम्नलिखित प्रश्न में भाग लिया है। सबसे पहले, यहाँ उदाहरण कोड है:

void print_string(const char * the_string)
{
    cout << the_string << endl;
}

int main () {
    print_string("What's up?");
}

उपरोक्त कोड में, print_string का पैरामीटर इसके बजाय हो सकता था const char * const the_string। इसके लिए कौन सा अधिक सही होगा?

मैं समझता हूं कि अंतर यह है कि एक निरंतर चरित्र के लिए एक संकेतक है, जबकि दूसरा एक निरंतर चरित्र के लिए एक सूचक है। लेकिन ये दोनों काम क्यों करते हैं? यह कब प्रासंगिक होगा?

जवाबों:


244

उत्तरार्द्ध आपको the_stringअंदर को संशोधित करने से रोकता है print_string। यह वास्तव में यहां उपयुक्त होगा, लेकिन शायद इस क्रिया ने डेवलपर को बंद कर दिया।

char* the_string: मैं charकिन the_stringबिंदुओं को बदल सकता हूं , और जिन बिंदुओं पर मैं संशोधित कर सकता हूं char

const char* the_string: मैं charकिन the_stringबिंदुओं को बदल सकता हूं , लेकिन मैं charउस बिंदु को संशोधित नहीं कर सकता ।

char* const the_string: मैं charकिन the_stringबिंदुओं को नहीं बदल सकता , लेकिन मैं charइसे जिस बिंदु पर संशोधित कर सकता हूं ।

const char* const the_string: मैं न तो charकिन the_stringबिंदुओं को बदल सकता हूं, न ही मैं charउस बिंदु को संशोधित कर सकता हूं ।


11
अंतिम वाक्य के लिए +1। कांस्टीट्यूशन सही है, लेकिन अच्छी तरह से इसके लायक है।
19

6
@ Xeo: आपका फ़ॉर्म और भी अधिक भ्रमित करने वाला है क्योंकि यह एक ट्रांसपोज़न है जो इसका अर्थ पूरी तरह से बदलने से दूर है। const char *बहुत बेहतर है क्योंकि constपूर्ण विपरीत पक्ष पर है।
आर .. गिटहब स्टॉप हेल्पिंग आईसीई

7
@ आर ..: ठीक है, कम से कम मेरे लिए यह नहीं है। दाएं से बाएं पढ़ने पर मुझे "पॉइंटर टू कॉन्स्ट चार" मिलता है। मेरे लिए, यह सिर्फ उस तरह से बेहतर महसूस करता है।
XIO

6
वैसे आप खुद को बेवकूफ बना रहे हैं क्योंकि सी टाइप्स अंदर से बाहर की ओर पढ़े जाते हैं, बाएं से दाएं नहीं। :-)
आर .. गिटहब स्टॉप हेल्पिंग आईसीई

11
मैं एक छोटे से शर्मिंदा मैं जाहिरा तौर पर केवल एक है जो इस बात को समझ नहीं करता हूँ हूँ ... लेकिन क्या "चार के बीच का अंतर है करने के लिए है जो यह बताते हैं" और "चार में जो यह बताते हैं"?
अभाव

138
  1. एक उत्परिवर्तनीय चरित्र के लिए परस्पर सूचक

    char *p;
  2. एक स्थिर चरित्र के लिए परस्पर सूचक

    const char *p;
  3. एक सतत चरित्र के लिए लगातार सूचक

    char * const p; 
  4. एक निरंतर चरित्र के लिए लगातार सूचक

    const char * const p;

ऐसा नहीं होना चाहिए: const char* p; --> constant pointer to mutable characterऔर char *const p; --> mutable pointer to constant character
PnotNP

2
@NulledPointer No. C ++ घोषणाएँ बाएँ से दाएँ बनाई जाती हैं। आप इस प्रकार पढ़ सकते हैं const char * p: "p एक चरित्र निरंतर का सूचक है" या एक निरंतर चरित्र के लिए एक परस्पर सूचक एक संकेत के रूप में जेम्स सही ढंग से बताता है। दूसरे के साथ भी वही :)।
समिदमारू

28

const char * constमतलब पॉइंटर और साथ ही पॉइंटर को जिस डेटा की ओर इशारा किया गया है, वह दोनों कांस्टेबल हैं!

const char *केवल मतलब है यह है कि सूचक जिस डेटा को इंगित करता है, वह const है। प्वाइंटर खुद कांस्टेबल नहीं है।

उदाहरण।

const char *p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //okay, changing the non-const pointer. 

const char * const p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //error, changing the const pointer. 

20

(मुझे पता है कि यह पुराना है लेकिन मैं वैसे भी साझा करना चाहता था।)

बस थॉमस मैथ्यू के जवाब पर विस्तार से बताना चाहते थे। C प्रकार की घोषणाओं का राइट-लेफ्ट नियम बहुत अधिक कहता है: पहचानकर्ता पर C प्रकार की घोषणा को पढ़ना शुरू करते हैं और जब आप नहीं कर सकते हैं तो दाएं और बाएं जाएं।

यह एक दो उदाहरणों के साथ सबसे अच्छा समझाया गया है:

उदाहरण 1

  • पहचानकर्ता पर शुरू करें, हम दाएं नहीं जा सकते इसलिए हम बाएं चलते हैं

    const char* const foo
                ^^^^^

    फू एक निरंतर है ...

  • जारी रखें छोड़ दिया

    const char* const foo
              ^

    फू एक निरंतर सूचक है ...

  • जारी रखें छोड़ दिया

    const char* const foo
          ^^^^

    फू एक निरंतर सूचक है चार ...

  • जारी रखें छोड़ दिया

    const char* const foo
    ^^^^^

    फू निरंतर (पूरा करने के लिए एक निरंतर सूचक है !)

उदाहरण 2

  • पहचानकर्ता पर शुरू करें, हम दाएं नहीं जा सकते इसलिए हम बाएं चलते हैं

    char* const foo
          ^^^^^

    फू एक निरंतर है ...

  • जारी रखें छोड़ दिया

    char* const foo
        ^

    फू एक निरंतर सूचक है ...

  • जारी रखें छोड़ दिया

    char* const foo
    ^^^^

    foo, char (पूर्ण!) के लिए एक निरंतर सूचक है ।

उदाहरण 1337

  • पहचानकर्ता पर शुरू करें, लेकिन अब हम सही जा सकते हैं!

    const char* const* (*foo[8])()
                            ^^^

    फू 8 की एक सरणी है ...

  • कोष्ठक मारो तो सही अब और नहीं जा सकते, बाएं जाओ

    const char* const* (*foo[8])()
                        ^

    फू 8 पॉइंटर की एक सरणी है ...

  • कोष्ठक के अंदर समाप्त, अब सही जा सकता है

    const char* const* (*foo[8])()
                                ^^

    foo, 8 पॉइंटर का एक फंक्शन है जो फंक्शन देता है ...

  • ज्यादा कुछ नहीं दाईं ओर, बाएं जाएं

    const char* const* (*foo[8])()
                     ^

    foo 8 पॉइंटर का एक फंक्शन है जो फंक्शन को पॉइंटर देता है ...

  • जारी रखें छोड़ दिया

    const char* const* (*foo[8])()
                ^^^^^

    foo कार्यों है कि एक करने के लिए एक सूचक रिटर्न के लिए 8 सूचक की एक सरणी है लगातार ...

  • जारी रखें छोड़ दिया

    const char* const* (*foo[8])()
              ^

    foo, 8 पॉइंटर का एक फंक्शन है, जो एक पॉइंटर को एक पॉइंटर को एक पॉइंटर को ...

  • जारी रखें छोड़ दिया

    const char* const* (*foo[8])()
          ^^^^

    foo कार्यों है कि एक के लिए एक निरंतर सूचक के लिए सूचक रिटर्न के लिए 8 सूचक की एक सरणी है चार ...

  • जारी रखें छोड़ दिया

    const char* const* (*foo[8])()
    ^^^^^

    foo, 8 पॉइंटर से लेकर फ़ंक्शंस तक एक पॉइंटर है जो एक पॉइंटर को पॉइंटर को एक निरंतर (पूर्ण!) तक लौटाता है ।

आगे की व्याख्या: http://www.unixwiz.net/techtips/reading-cdecl.html


CMIIW, const char * const foo को char const * const फू के बराबर होना चाहिए?
लुओचेनहुआन

@luochenhuan हाँ, वास्तव में वे हैं।
गैरेट

12

कई लोग सुझाव देते हैं कि राइट से लेफ्ट तक टाइप टाइप करें।

const char * // Pointer to a `char` that is constant, it can't be changed.
const char * const // A const pointer to const data.

दोनों रूपों में, सूचक निरंतर या केवल-पढ़ने वाले डेटा की ओर इशारा करता है।

दूसरे रूप में, सूचक को बदला नहीं जा सकता है; सूचक हमेशा एक ही स्थान पर इंगित करेगा।


3

अंतर यह है कि अतिरिक्त constके बिना प्रोग्रामर बदल सकता है, विधि के अंदर, जहां सूचक इंगित करता है; उदाहरण के लिए:

 void print_string(const char * the_string)
 {
    cout << the_string << endl;
    //....
    the_string = another_string();
    //....

 }

अगर हस्ताक्षर होते तो वह अवैध होता void print_string(const char * const the_string)

कई प्रोग्रामर अतिरिक्त constशब्द भी महसूस करते हैं (ज्यादातर परिदृश्य में) अतिरिक्त कीवर्ड और इसे छोड़ दें, भले ही यह शब्दार्थ सही हो।


2

उत्तरार्द्ध में आप पहले से ही सूचक और चरित्र दोनों को संशोधित नहीं करने की गारंटी दे रहे हैं, केवल आप गारंटी देते हैं कि सामग्री नहीं बदलेगी लेकिन आप सूचक को चारों ओर ले जा सकते हैं


अंतिम कास्ट के बिना आह, मैं वास्तव में एक पूरी तरह से अलग स्ट्रिंग को इंगित करने के लिए सूचक सेट कर सकता था?
चित्र

हां, उस अंतिम कॉन्स्ट के बिना आप पॉइंटर अंकगणित द्वारा कुछ पुनरावृति करने के लिए पैरामीटर पॉइंटर का उपयोग कर सकते हैं, जहां यदि वह कॉन्स्टेंस था तो आपको अपना पॉइंटर बनाना होगा जो उस पैरामीटर की एक प्रति है।
यीशु रामोस

2

कोई कारण नहीं है कि या तो कोई काम नहीं करेगा। सबprint_string() प्रिंट मूल्य है। यह इसे संशोधित करने का प्रयास नहीं करता है।

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

जहाँ तक सटीक सिंटैक्स की बात है, आप यह इंगित करना चाहते हैं कि किस प्रकार के तर्कों को फ़ंक्शन में पास किया जाना "सुरक्षित" है।


2

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


2

const char *इसका मतलब है कि आप पॉइंटर का उपयोग करने के लिए इंगित करने के लिए उपयोग नहीं कर सकते। आप सूचक को किसी अन्य चीज़ की ओर इंगित करने के लिए बदल सकते हैं, हालाँकि।

विचार करें:

const char * promptTextWithDefault(const char * text)
{
    if ((text == NULL) || (*text == '\0'))
        text = "C>";
    return text;
}

पैरामीटर कांस्ट चार्ज करने के लिए एक गैर-कास्ट पॉइंटर है, इसलिए इसे दूसरे const char *मूल्य (जैसे एक स्थिर स्ट्रिंग) में बदला जा सकता है । यदि, हालांकि, हमने गलती से लिखा है*text = '\0' तो हमें एक संकलन त्रुटि मिलेगी।

यकीनन, यदि आप उस पैरामीटर को बदलने का इरादा नहीं रखते हैं जो पैरामीटर इंगित कर रहा है, तो आप पैरामीटर बना सकते हैं const char * const text, लेकिन ऐसा करना आम नहीं है। हम आमतौर पर फ़ंक्शंस को पैरामीटर में दिए गए मानों को बदलने की अनुमति देते हैं (क्योंकि हम मान से मापदंडों को पास करते हैं, कोई भी परिवर्तन कॉलर को प्रभावित नहीं करता है)।

बीटीडब्ल्यू: यह बचने के लिए अच्छा अभ्यास है char const *क्योंकि यह अक्सर गलत होता है - इसका मतलब उसी के समान है const char *, लेकिन बहुत से लोग इसे अर्थ के रूप में पढ़ते हैं char * const


वाह! मैं अपने const char *और हस्ताक्षर के बीच अंतर का पता लगाने की कोशिश कर रहा था char const *- जिस तरह से आपने अपने बीटीडब्लू को शब्द दिया था उससे वास्तव में मदद मिली!
ऋषि

1

लगभग सभी अन्य उत्तर सही हैं, लेकिन वे इसके एक पहलू को याद करते हैं: जब आप constकिसी फ़ंक्शन घोषणा में एक पैरामीटर पर अतिरिक्त का उपयोग करते हैं , तो कंपाइलर अनिवार्य रूप से इसे अनदेखा करेगा। एक पल के लिए, आइए एक संकेतक होने के नाते अपने उदाहरण की जटिलता को अनदेखा करें और बस एक का उपयोग करें int

void foo(const int x);

के रूप में एक ही कार्य घोषित करता है

void foo(int x);

केवल फ़ंक्शन की परिभाषा में अतिरिक्त constसार्थक है:

void foo(const int x) {
    // do something with x here, but you cannot change it
}

यह परिभाषा उपरोक्त घोषणाओं में से एक है। फोन करने वाले की परवाह नहीं xहैconst --that एक कार्यान्वयन विस्तार है कि कॉल स्थल पर प्रासंगिक नहीं है।

यदि आपके पास डेटा के constलिए एक पॉइंटर है const, तो वही नियम लागू होते हैं:

// these declarations are equivalent
void print_string(const char * const the_string);
void print_string(const char * the_string);

// In this definition, you cannot change the value of the pointer within the
// body of the function.  It's essentially a const local variable.
void print_string(const char * const the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // COMPILER ERROR HERE
}

// In this definition, you can change the value of the pointer (but you 
// still can't change the data it's pointed to).  And even if you change
// the_string, that has no effect outside this function.
void print_string(const char * the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // OK, but not observable outside this func
}

कुछ सी ++ प्रोग्रामर मापदंडों को बनाने के लिए परेशान करते हैं const, तब भी जब वे हो सकते हैं, भले ही वे पैरामीटर संकेत हों।


"कंपाइलर अनिवार्य रूप से इसे अनदेखा करेगा" हमेशा सच नहीं होता है, विजुअल C ++ 2015 यदि आप constअपने फ़ंक्शन पैरामीटर को अतिरिक्त रूप से परिभाषा में जोड़ते हैं तो चेतावनी का उत्पादन करेंगे लेकिन घोषणा नहीं।
किरणमाई ray

@ रायमई 97: मुझे लगता है कि 2015 के कंपाइलर में एक बग है, लेकिन मेरे पास टेस्ट करने के लिए 2015 नहीं है। मैं 2017 में वर्णित के रूप में काम करता हूं, जो, कुछ मानकों के विशेषज्ञों के साथ मेरी बातचीत के अनुसार, अपेक्षित व्यवहार है।
एड्रियन मैक्कार्थी

-1

दोनों के बीच अंतर यह है कि चार * किसी भी मनमाने ढंग से सूचक को इंगित कर सकते हैं। कॉन्स्ट चर * इसके विपरीत, निष्पादन योग्य के डेटा अनुभाग में परिभाषित स्थिरांक को इंगित करता है। और, इस तरह, आप एक कास्ट चार * स्ट्रिंग के चरित्र मूल्यों को संशोधित नहीं कर सकते।


मैं char * और const char * के बीच अंतर नहीं पूछ रहा हूँ। मैं स्थिरांक चार के बीच पूछ रहा हूँ * और स्थिरांक चार * स्थिरांक
pict

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