Const int *, const int * const, और int const * के बीच अंतर क्या है?


1354

मैं हमेशा कैसे उपयोग करने के लिए गंदगी const int*, const int * constहै, और int const *सही ढंग से। क्या नियमों का एक सेट है जिसे आप परिभाषित कर सकते हैं और क्या नहीं कर सकते हैं?

मैं असाइनमेंट के संदर्भ में सभी कार्य करना चाहता हूं और सभी कार्य करने के लिए, आदि।


175
अधिकांश C और C ++ घोषणाओं को समझने के लिए आप "दक्षिणावर्त / सर्पिल नियम" का उपयोग कर सकते हैं ।
जेम्स मैकनेलिस

52
cdecl.org एक बेहतरीन वेबसाइट है, जो आपके लिए C घोषणाओं का ऑटो-अनुवाद करती है।
डेव गलाघेर

6
@ कैलेमरियस: शुरू जहां टाइप-नाम है / होना चाहिए, जब आप कर सकते हैं तो दाएं घुमाएं , जब आपको करना चाहिएint *(*)(char const * const)। कोष्ठक के दाईं ओर शुरू करें *फिर हमें बाएं चलना होगा pointer:। Parens के बाहर, हम सही स्थानांतरित कर सकते हैं pointer to function of ...:। फिर हमें बाएं चलना होगा pointer to function of ... that returns pointer to int:। पैरामीटर ( ...) को विस्तारित करने के लिए दोहराएँ pointer to function of (constant pointer to constant char) that returns pointer to int:। पास्कल जैसी आसान पढ़ने वाली भाषा में समतुल्य एक पंक्ति की घोषणा क्या होगी?
मार्क के कोवन

1
@ मर्ककॉवन पास्कल में यह कुछ इस तरह होगा function(x:^char):^int। फ़ंक्शन प्रकार एक फ़ंक्शन के लिए एक संकेतक हैं, इसलिए इसे निर्दिष्ट करने की कोई आवश्यकता नहीं है, और पास्कल कॉन्स्ट शुद्धता को लागू नहीं करता है। इसे बाएं से दाएं पढ़ा जा सकता है।
कैलमेरियस

5
"कॉन्स्ट" के बाईं ओर पहली चीज जो स्थिर है। यदि "कॉन्स्ट" सबसे बाईं ओर की चीज है, तो इसके दाईं ओर पहली चीज जो स्थिर है।
कपकेक

जवाबों:


2205

इसे पीछे की ओर पढ़ें ( क्लॉकवाइज / सर्पिल नियम द्वारा संचालित ):

  • int* - सूचक को int
  • int const * - पॉइंटर टू कॉन्स्ट इंट
  • int * const - कॉन्स्ट पॉइंटर टू इंट
  • int const * const - कॉन्स्ट पॉइंटर to const int

अब पहले constप्रकार के दोनों तरफ हो सकता है:

  • const int * == int const *
  • const int * const == int const * const

यदि आप वास्तव में पागल हो जाना चाहते हैं तो आप इस तरह की चीजें कर सकते हैं:

  • int ** - सूचक सूचक to int
  • int ** const - एक कॉन्स्टेंट पॉइंटर को पॉइंटर से इंट में
  • int * const * - एक संकेतक एक कास्ट पॉइंटर को एक इंट का सूचक
  • int const ** - पॉइंटर को पॉइंटर से कॉन्स्टेंट को
  • int * const * const - एक कांस्टेबल पॉइंटर को एक कॉन्टेक्ट पॉइंटर को इंट में
  • ...

और यह सुनिश्चित करने के लिए कि हम निम्नलिखित के अर्थ पर स्पष्ट हैं const:

int a = 5, b = 10, c = 15;

const int* foo;     // pointer to constant int.
foo = &a;           // assignment to where foo points to.

/* dummy statement*/
*foo = 6;           // the value of a can´t get changed through the pointer.

foo = &b;           // the pointer foo can be changed.



int *const bar = &c;  // constant pointer to int 
                      // note, you actually need to set the pointer 
                      // here because you can't change it later ;)

*bar = 16;            // the value of c can be changed through the pointer.    

/* dummy statement*/
bar = &a;             // not possible because bar is a constant pointer.           

fooएक स्थिर पूर्णांक के लिए एक चर सूचक है। यह आपको वह बदलने देता है जो आप इंगित करते हैं लेकिन उस मूल्य को नहीं जो आप इंगित करते हैं। अक्सर यह सी-स्टाइल स्ट्रिंग्स के साथ देखा जाता है जहां आपके पास एक संकेतक है const char। आप जिस स्ट्रिंग को इंगित करते हैं उसे बदल सकते हैं लेकिन आप इन स्ट्रिंग्स की सामग्री को नहीं बदल सकते। यह महत्वपूर्ण है जब स्ट्रिंग खुद एक प्रोग्राम के डेटा सेगमेंट में है और इसे बदला नहीं जाना चाहिए।

barएक मूल्य के लिए एक निरंतर या निश्चित सूचक है जिसे बदला जा सकता है। यह बिना अतिरिक्त चीनी के चीनी के संदर्भ के समान है। इस तथ्य के कारण, आमतौर पर आप एक संदर्भ का उपयोग करेंगे जहां आप एक T* constपॉइंटर का उपयोग करेंगे जब तक कि आपको NULLपॉइंटर्स की अनुमति देने की आवश्यकता न हो ।


480
मैं अंगूठे के एक नियम को जोड़ना चाहता हूं जो आपको यह याद रखने में मदद कर सकता है कि कैसे पता चलता है कि 'कास्ट' पॉइंटर पर या इंगित किए गए डेटा पर लागू होता है: कथन को तारांकन चिह्न पर विभाजित करें, फिर, यदि कॉन्स्ट्रेस कीवर्ड बाएं हिस्से में दिखाई देता है (जैसे 'const int * foo') - यह इंगित डेटा से संबंधित है, यदि यह सही भाग में है ('int * const bar') - यह पॉइंटर के बारे में है।
माइकल

14
@ मिचेल: कॉन्ड नियम को याद रखने / समझने के लिए इस तरह के एक सरल नियम के लिए माइकल को कुडोस।
शिवाबुध 19

10
@ जेफ़्री: इसे पीछे की ओर पढ़ें जब तक कोई कोष्ठक न हो। फिर, अच्छी तरह से ... टाइप्डाइफ्स का उपयोग करें
डक

12
+1, हालांकि एक बेहतर सारांश होगा: सूचक घोषणाओं को पीछे की ओर पढ़ें , जिसका अर्थ है, @Michael के कथन के करीब: पहले तारांकन पर सामान्य बाएं से दाएं पढ़ना बंद करें ।
वुल्फ

3
@gedamial यह करता है, यह ठीक काम करता है, लेकिन आपको इसे उसी समय निर्दिष्ट करना चाहिए जब आप इसे घोषित करते हैं (क्योंकि आप "कॉन्स्टेंट पॉइंटर" को पुन: असाइन नहीं कर सकते हैं)। const int x = 0; const int *const px = &x; const int *const *const p = &px;ठीक काम करता है।
रस्ताजेडी ०

356

जो लोग दक्षिणावर्त / सर्पिल नियम के बारे में नहीं जानते हैं उनके लिए: चर के नाम से शुरू करें, घड़ी की दिशा में (इस मामले में, पीछे की ओर जाएं) अगले सूचक या प्रकार पर जाएं । अभिव्यक्ति समाप्त होने तक दोहराएं।

यहाँ एक डेमो है:

सूचक को int

const सूचक int const

सूचक int const के लिए

पॉइंटर इंट कास्ट

const सूचक int


8
@ जटिल उदाहरण के लिए लिंक की अनुमति नहीं है। क्या आप इसे सीधे यहाँ पोस्ट कर सकते हैं, या देखने के प्रतिबंध को हटा सकते हैं?
R71

8
@ यह सभी खुली पहुँच अनुमतियाँ हुआ करता था ... मैं लेख नहीं लिखा था और अपने आप को पहुँच अनुमति नहीं है, दुर्भाग्य से। हालाँकि, यहाँ लेख का एक संग्रहीत संस्करण है जो अभी भी काम करता है: आर्काइव .is
Jan Rüegg

8
जटिल उदाहरण अभी भी बाएं से दाएं है, लेकिन इसमें कोष्ठक को हल करना शामिल है, जो सामान्य रूप से होगा। पूरे दक्षिणावर्त सर्पिल बात यह है कि किसी भी आसान नहीं है।
मैथ्यू

4
अंतिम उदाहरण: void (*signal(int, void (*fp)(int)))(int);
आर्काइव

3
इस नियम पर भरोसा न करें। यह सार्वभौमिक नहीं है। कुछ मामले ऐसे हैं जहां यह विफल हो जाता है।
शाम

150

मुझे लगता है कि यहां सब कुछ पहले से ही उत्तर दिया गया है, लेकिन मैं सिर्फ यह जोड़ना चाहता हूं कि आपको typedefएस से सावधान रहना चाहिए ! वे सिर्फ पाठ प्रतिस्थापन नहीं हैं।

उदाहरण के लिए:

typedef char *ASTRING;
const ASTRING astring;

का प्रकार astringहै char * const, नहीं const char *। यह एक कारण है जो मैं हमेशा constटाइप के दाईं ओर रखता हूं , और शुरुआत में कभी नहीं।


20
और मेरे लिए यही कारण है कि मैं कभी भी टाइपकाफ पॉइंटर्स नहीं लिखता। मुझे चीजों में लाभ दिखाई नहीं देता typedef int* PINT( जैसे मैं इसकी कुछ चीज़ों को सी में प्रथाओं से आया था और कई डेवलपर्स इसे करते रहे)। महान, मैंने प्रतिस्थापित किया है कि *ए के साथ P, यह टाइपिंग को गति नहीं देता है, साथ ही आपके द्वारा बताई गई समस्या को पेश करता है।
मफ्फेन

1
@ मीपन - मैं वह देख सकता हूँ। हालाँकि, मुझे यह प्रतीत होता है कि एक असाधारण वाक्यविन्यास नियम ("कॉन्स्ट" प्लेसमेंट) का उपयोग करने के लिए एक अच्छी भाषा सुविधा से बचने के लिए पीछे की तरह लगता है, बल्कि असाधारण वाक्य-विन्यास नियम का उपयोग करने से बचने के लिए ताकि आप सुरक्षित रूप से इस भाषा सुविधा का उपयोग कर सकें ।
TED

6
@ मीफेन PINTवास्तव में एक टाइप्डिफ की बजाय गूंगा उपयोग है, विशेष रूप से क्यूज यह मुझे लगता है कि सिस्टम स्टोरेज मेमोरी के लिए बीयर का उपयोग करता है। हालांकि कार्यों के लिए संकेत के साथ काम करने के लिए टाइपेडिफ एस बहुत उपयोगी हैं।
अप्रूवलडार्कनेस

5
@KazDragon धन्यवाद! इसके बिना, मैं Win32 एपीआई में उन सभी टाइप किए गए PVOID, LPTSTRसामान के साथ गड़बड़ कर दिया होता !
डेविड ली

2
@ मीफ़ेन: मुझे कुछ विरासत वाले मैक्रोज़ का उपयोग करते समय कई बार pSomething का उपयोग करना पड़ा है जो एक प्रकार को स्वीकार करने के लिए लिखे गए थे, लेकिन यदि कोई एकल अल्फ़ान्यूमेरिक पहचानकर्ता नहीं था, तो टूट जाएगा। :)
ग्रू

56

बहुत ज्यादा की तरह सभी ने बताया:

क्या अंतर है const X* p, X* const pऔर const X* const p?

आपको दाएं से बाएं ओर सूचक घोषणाओं को पढ़ना होगा।

  • const X* p "p एक X का अर्थ है जो const है": X ऑब्जेक्ट को p के माध्यम से नहीं बदला जा सकता है।

  • X* const p इसका मतलब है "पी एक एक्स के लिए एक कॉन्स्टेंट पॉइंटर है जो नॉन-कास्ट है": आप पॉइंटर को स्वयं नहीं बदल सकते, लेकिन आप एक्स ऑब्जेक्ट को पी के माध्यम से बदल सकते हैं।

  • const X* const p इसका मतलब है "पी एक एक्स के लिए एक कास्ट पॉइंटर है जो कॉन्स्टेबल है": आप पॉइंटर पी को खुद नहीं बदल सकते, न ही आप एक्स ऑब्जेक्ट को पी के माध्यम से बदल सकते हैं।


3
यह मत भूलो const X* p;== X const * p;जैसा कि"p points to an X that is const": the X object can't be changed via p.
जेसी चिशोल्म

सरल और अच्छा अन्वेषण!
एडिसन लो

50
  1. लगातार संदर्भ:

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

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
  2. लगातार संकेत

    एक बार एक निरंतर सूचक एक चर की ओर इशारा करता है तो यह किसी अन्य चर की ओर इशारा नहीं कर सकता है।

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
  3. सूचक को स्थिर करने के लिए

    एक पॉइंटर जिसके माध्यम से कोई भी उस चर के मान को नहीं बदल सकता है, जिसे पॉइंटर को स्थिरांक के रूप में जाना जाता है।

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
  4. एक स्थिर करने के लिए लगातार सूचक

    एक स्थिरांक के लिए एक निरंतर सूचक एक सूचक है जो न तो उस पते को बदल सकता है जिसे वह इंगित कर रहा है और न ही उस पते पर रखे गए मूल्य को बदल सकता है।

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error

20

सामान्य नियम यह है कि constकीवर्ड उस पर लागू होता है जो उसे तुरंत पहले कर देता है। अपवाद, एक शुरुआत constइस प्रकार लागू होती है।

  • const int*के रूप में ही है int const*और इसका मतलब है "लगातार अंतर करने के लिए सूचक"
  • const int* constके रूप में ही है int const* constऔर इसका मतलब है "निरंतर सूचक के लिए निरंतर सूचक"

संपादित करें: डॉस और डॉनट्स के लिए, यदि यह उत्तर पर्याप्त नहीं है, तो क्या आप जो चाहते हैं, उसके बारे में अधिक सटीक हो सकते हैं?


19

यह प्रश्न ठीक-ठीक दिखाता है कि मुझे अपने प्रश्न का उल्लेख करने का तरीका पसंद क्यों है?

संक्षेप में, मुझे नियम को याद रखने का सबसे आसान तरीका यह है कि "कॉन्स्ट" उस चीज के बाद जाता है जो उस पर लागू होता है। तो आपके प्रश्न में, "int const *" का अर्थ है कि int स्थिर है, जबकि "int * const" का अर्थ होगा कि सूचक स्थिर है।

अगर कोई इसे बहुत सामने रखने का फैसला करता है (जैसे: "const int *"), तो उस मामले में एक विशेष अपवाद के रूप में यह उसके बाद की बात पर लागू होता है।

बहुत से लोग उस विशेष अपवाद का उपयोग करना पसंद करते हैं क्योंकि उन्हें लगता है कि यह अच्छा लग रहा है। मैं इसे नापसंद करता हूं, क्योंकि यह एक अपवाद है, और इस तरह चीजों को भ्रमित करता है।


2
मैं इस मुद्दे पर फटा हुआ हूँ। तार्किक रूप से यह समझ में आता है। हालाँकि अधिकांश c ++ डेवलपर लिखते हैं const T*और यह अधिक स्वाभाविक हो गया है। आप कितनी भी बार किसी T* constभी रास्ते का उपयोग करते हैं , आमतौर पर एक संदर्भ बस ठीक होगा। मैं यह सब एक बार जब चाहा boost::shared_ptr<const T>और बदले में लिखा था const boost::shared_ptr<T>। एक ही अलग संदर्भ में एक ही मुद्दा।
मैट की कीमत

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

1
टाइप के दाईं ओर कास्ट रखने का एक और अच्छा फायदा यह है कि अब किसी भी लेफ्ट के लिए सब कुछ constउसी प्रकार का है जो कॉन्स्टेबल है, और उसके राइट में सब कुछ वह है जो वास्तव में कॉन्स्ट है। int const * const * p;एक उदाहरण के रूप में लें । नहीं, मैं आमतौर पर ऐसा नहीं लिखता, यह सिर्फ एक उदाहरण है। पहला const: int int, और int वह है जो const है जो कि const पॉइंटर की सामग्री है जो की सामग्री है p। दूसरा constनक्षत्र : प्रकार सूचक है int, const oblect की सामग्री हैp
dgnuff

18

का सरल उपयोग const

सबसे सरल उपयोग एक नामित स्थिरांक घोषित करना है। ऐसा करने के लिए, एक स्थिर घोषित करता है जैसे कि वह एक चर था, लेकिन constइससे पहले जोड़ें । किसी को इसे कंस्ट्रक्टर में तुरंत इनिशियलाइज़ करना होगा, क्योंकि निश्चित रूप से, कोई बाद में मान को सेट नहीं कर सकता है क्योंकि यह इसे बदल देगा। उदाहरण के लिए:

const int Constant1=96; 

एक पूर्णांक स्थिरांक बनाएगा, जिसे अकल्पनीय रूप से कहा जाएगा Constant1मान 96 के साथ ।

ऐसे स्थिरांक पैरामीटर के लिए उपयोगी होते हैं जो प्रोग्राम में उपयोग किए जाते हैं लेकिन प्रोग्राम संकलित होने के बाद उन्हें बदलने की आवश्यकता नहीं होती है। C प्रीप्रोसेसर पर प्रोग्रामर्स के लिए इसका एक फायदा है#define कमांड है कि यह कंपाइलर द्वारा ही समझा और उपयोग किया जाता है, मुख्य कंपाइलर तक पहुंचने से पहले प्रीप्रोसेसर द्वारा केवल प्रोग्राम टेक्स्ट में प्रतिस्थापित नहीं किया जाता है, इसलिए त्रुटि संदेश बहुत अधिक सहायक होते हैं।

यह पॉइंटर्स के साथ भी काम करता है, लेकिन किसी को सावधान रहना होगा कि constयह निर्धारित करने के लिए कि पॉइंटर या यह किस बिंदु पर स्थिर है या दोनों। उदाहरण के लिए:

const int * Constant2 

घोषित करता है कि Constant2एक स्थिर पूर्णांक के लिए चर सूचक है और:

int const * Constant2

एक वैकल्पिक वाक्यविन्यास है जो वही करता है, जबकि

int * const Constant3

घोषित करता है कि Constant3एक चर पूर्णांक के लिए निरंतर सूचक है और

int const * const Constant4

घोषित करता है कि Constant4एक स्थिर पूर्णांक के लिए निरंतर सूचक है। मूल रूप से left कास्ट ’अपने तत्काल बाईं ओर जो कुछ भी है उस पर लागू होता है (इसके अलावा अगर वहाँ कुछ भी नहीं है तो यह उस स्थिति में लागू होता है जो इसके तत्काल बाईं ओर है)।

रेफरी: http://duramecho.com/ComputerInformation/WhyHowCppConst.html


9

जब तक मैं C ++ गुरु स्कॉट मेयर्स की इस पुस्तक को लेकर आया, तब तक मुझे आप पर भी यही संदेह था । इस पुस्तक में तीसरे आइटम का संदर्भ लें जहां वह उपयोग करने के बारे में विवरण में बात करता है const

बस इस सलाह का पालन करें

  1. यदि शब्द constतारांकन चिह्न के बाईं ओर प्रकट होता है, तो जो इंगित किया गया है वह स्थिर है
  2. यदि शब्द constतारांकन चिह्न के दाईं ओर दिखाई देता है, तो सूचक स्वयं स्थिर है
  3. यदि constदोनों तरफ दिखाई देता है, तो दोनों स्थिर हैं

7

यह सरल है लेकिन मुश्किल है। कृपया ध्यान दें कि हम स्वैप कर सकते हैं const(किसी भी डेटा प्रकार के साथ क्वालीफायर int, char,float , आदि)।

आइए नीचे दिए गए उदाहरण देखें।


const int *p==> *pकेवल पढ़ने के लिए [ pएक निरंतर पूर्णांक के लिए एक संकेतक है]

int const *p ==> *pकेवल पढ़ने के लिए [ pएक निरंतर पूर्णांक के लिए एक संकेतक है]


int *p const==> गलत बयान। कंपाइलर एक सिंटैक्स त्रुटि फेंकता है।

int *const p==> pकेवल-पढ़ने के लिए है [p एक पूर्णांक के लिए एक निरंतर सूचक है]। जैसा कि सूचक pयहां केवल पढ़ा जाता है, घोषणा और परिभाषा एक ही स्थान पर होनी चाहिए।


const int *p const ==> गलत बयान। कंपाइलर एक सिंटैक्स त्रुटि फेंकता है।

const int const *p ==> *pकेवल-पढ़ने के लिए है

const int *const p1 ==> *pऔर pकेवल पढ़ने के लिए [ pएक निरंतर पूर्णांक के लिए एक निरंतर सूचक है]। सूचक के रूप मेंpयहां केवल पढ़ा जाता है, घोषणा और परिभाषा एक ही स्थान पर होनी चाहिए।


int const *p const ==> गलत बयान। कंपाइलर एक सिंटैक्स त्रुटि फेंकता है।

int const int *p ==> गलत बयान। कंपाइलर एक सिंटैक्स त्रुटि फेंकता है।

int const const *p ==> *p केवल-पढ़ने के लिए है और इसके बराबर हैint const *p

int const *const p ==> *pऔर pकेवल पढ़ने के लिए [ pएक निरंतर पूर्णांक के लिए एक निरंतर सूचक है]। जैसा कि सूचक pयहां केवल पढ़ा जाता है, घोषणा और परिभाषा एक ही स्थान पर होनी चाहिए।


6

C ++ में कॉन्स्टेंट शुद्धता के आसपास कई अन्य सूक्ष्म बिंदु हैं। मुझे लगता है कि यहाँ सवाल केवल C के बारे में है, लेकिन मैं टैग C ++ के बाद से कुछ संबंधित उदाहरण दूंगा:

  • आप अक्सर स्ट्रिंग्स जैसे बड़े तर्क पारित करते हैं TYPE const &जो ऑब्जेक्ट को संशोधित या कॉपी होने से रोकता है। उदाहरण :

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    लेकिन TYPE & constनिरर्थक है क्योंकि संदर्भ हमेशा कास्ट होते हैं।

  • आपको हमेशा क्लास के तरीकों को लेबल करना चाहिए जो क्लास को संशोधित नहीं करते हैं const, अन्यथा आप किसी TYPE const &संदर्भ से विधि को कॉल नहीं कर सकते । उदाहरण :

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • ऐसी सामान्य स्थितियां हैं, जहां रिटर्न वैल्यू और मेथड दोनों कांस्टेबल होने चाहिए। उदाहरण :

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    वास्तव में, कास्ट तरीकों को संदर्भ-से-गैर-कॉन्स्टेंस के रूप में आंतरिक वर्ग डेटा वापस नहीं करना चाहिए।

  • नतीजतन, किसी को अक्सर कब्ज और नॉन-कास्ट विधि दोनों को ओवरलोडिंग का उपयोग करके बनाना चाहिए। उदाहरण के लिए, यदि आप परिभाषित करते हैं T const& operator[] (unsigned i) const;, तो आप संभवत: इसके द्वारा दिए गए गैर-कास्ट संस्करण को भी चाहेंगे:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, C में कोई कास्ट फ़ंक्शन नहीं हैं, गैर-सदस्य फ़ंक्शंस स्वयं C ++ में कॉन्स्टेबल नहीं हो सकते हैं, कॉस्ट विधियों के साइड इफेक्ट्स हो सकते हैं, और कंपाइलर डुप्लिकेट फ़ंक्शन कॉल से बचने के लिए कॉस्ट फ़ंक्शंस का उपयोग नहीं कर सकते हैं। वास्तव में, यहां तक ​​कि एक साधारण int const &संदर्भ भी उस मूल्य को देख सकता है जिसके संदर्भ में इसे कहीं और बदला जाए।


6

मूल डिजाइनरों द्वारा सी और सी ++ घोषणा सिंटैक्स को बार-बार एक असफल प्रयोग के रूप में वर्णित किया गया है।

इसके बजाय, आइए "सूचक" नाम लिखें Type; मैं इसे कॉल करूंगा Ptr_:

template< class Type >
using Ptr_ = Type*;

अब Ptr_<char>एक सूचक है char

Ptr_<const char>के लिए एक सूचक है const char

और के const Ptr_<const char>लिए एक constसूचक है const char

वहाँ।

यहां छवि विवरण दर्ज करें


3
क्या आपके पास पहले वाक्य के लिए एक उद्धरण है?
sp2danny

@ sp2danny: Googling "C वाक्यविन्यास विफल प्रयोग" केवल Bjarne Stroustrup के साथ कई साक्षात्कारों में खांसी करता है, जहां वह उस दिशा में अपनी राय व्यक्त करता है, उदाहरण के लिए "मैं C घोषणाकर्ता वाक्यविन्यास को एक प्रयोग मानता हूं" Slashdot साक्षात्कार में। इसलिए मेरे पास सी के मूल डिजाइनरों के दृष्टिकोण के बारे में दावे के लिए कोई संदर्भ नहीं है। मुझे लगता है कि यह एक पर्याप्त रूप से मजबूत अनुसंधान प्रयास द्वारा पाया जा सकता है, या शायद उन्हें पूछकर अप्रतिबंधित हो सकता है, लेकिन मुझे लगता है कि यह अब जिस तरह से बेहतर है। दावे के उस हिस्से के साथ, अभी भी अनिर्दिष्ट और संभावना सच है :)
चीयर्स और एचटीटी। - अल्फ

1
"मूल डिजाइनरों द्वारा सी और सी ++ घोषणा सिंटैक्स को बार-बार एक असफल प्रयोग के रूप में वर्णित किया गया है।" C के लिए गलत कृपया C के बारे में अपना वाक्य बदलें या कुछ उद्धरण प्रदान करें।
स्टारगेट

3
@Stargateur: जाहिर तौर पर आपने पूर्ववर्ती टिप्पणियों को पढ़ा है और पाया है कि आप कुछ ऐसा कर सकते हैं जिसका आप लाभ उठा सकते हैं। आपका जीवन मंगलमय हो। वैसे भी, मेरे जैसे पुराने समय के लोग बहुत याद करते हैं कि हम बहुत समय लेने वाले शोध में उलझे बिना साबित नहीं हो सकते। आप सिर्फ मेरा वचन ले सकते हैं।
चीयर्स एंड हीथ। -


6

मेरे लिए, constअर्थात यह LEFT या RIGHT या LEFT और RIGHT दोनों के सापेक्ष प्रतीत होता है, जो *मुझे वास्तविक अर्थ निकालने में मदद करता है।

  1. एक constके बाईं ओर *इंगित करता है वस्तु बताया कि द्वारा सूचक एक है constवस्तु।

  2. A constका अधिकार *इंगित करता है कि सूचक एक constसूचक है।

निम्न तालिका स्टैनफोर्ड CS106L स्टैंडर्ड C ++ प्रोग्रामिंग लेबोरेटरी कोर्स रीडर से ली गई है।

यहां छवि विवरण दर्ज करें


3

यह ज्यादातर दूसरी पंक्ति को संबोधित करता है: सर्वोत्तम अभ्यास, असाइनमेंट, फ़ंक्शन पैरामीटर आदि।

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

प्लेग की तरह const_cast <> से बचें। इसके लिए एक या दो वैध उपयोग के मामले हैं, लेकिन वे बहुत कम हैं और बीच में बहुत दूर हैं। यदि आप किसी constऑब्जेक्ट को बदलने की कोशिश कर रहे हैं , तो आप यह जानने के लिए बहुत बेहतर करेंगे कि जिसने भी इसे constपहली गति में घोषित किया है और जो बात होनी चाहिए, उस पर आम सहमति तक पहुंचने के लिए उनके साथ बात करें।

जो असाइनमेंट में बहुत करीने से ले जाता है। आप किसी चीज में तभी असाइन कर सकते हैं जब वह नॉन-कास्ट हो। यदि आप किसी ऐसी चीज़ में असाइन करना चाहते हैं, जो कॉन्स्टेबल है, तो ऊपर देखें। याद रखें कि घोषणाओं में int const *foo;और int * const bar;विभिन्न चीजें हैं const- यहां अन्य उत्तरों ने उस मुद्दे को विशेष रूप से कवर किया है, इसलिए मैं इसमें नहीं जाऊंगा।

समारोह पैरामीटर:

मान से पास करें: जैसे void func(int param)आप कॉलिंग साइट पर एक तरह से या दूसरे तरीके से परवाह नहीं करते हैं। यह तर्क दिया जा सकता है कि फ़ंक्शन को घोषित करने के लिए उपयोग के मामले हैं, void func(int const param)लेकिन इससे कॉल करने वाले पर कोई प्रभाव नहीं पड़ता है, केवल फ़ंक्शन पर ही, इसमें जो भी मान पास होता है उसे कॉल के दौरान फ़ंक्शन द्वारा नहीं बदला जा सकता है।

संदर्भ से गुजारें: उदाहरण के लिए void func(int &param)अब यह एक फर्क पड़ता है। जैसा कि अभी घोषित किया गया funcहै कि परिवर्तन की अनुमति है param, और किसी भी कॉलिंग साइट को परिणामों से निपटने के लिए तैयार होना चाहिए। void func(int const &param)अनुबंध को बदलने की घोषणा को बदलना , और गारंटी देता है कि funcअब बदल नहीं सकता है param, जिसका अर्थ है कि जो बीत चुका है वह वापस आ जाएगा। जैसा कि अन्य ने उल्लेख किया है कि यह एक बड़ी वस्तु को सस्ते में पारित करने के लिए बहुत उपयोगी है जिसे आप बदलना नहीं चाहते हैं। एक संदर्भ को पास करना एक बड़ी वस्तु को मूल्य से पारित करने की तुलना में बहुत सस्ता है।

सूचक को पार करें: उदाहरण के लिए void func(int *param)और void func(int const *param)इन दो, सुंदर उनके संदर्भ समकक्षों के साथ ज्यादा पर्याय बन गया है चेतावनी बुलाया समारोह अब के लिए जाँच करने की जरूरत है कि के साथ nullptrजब तक कुछ अन्य संविदात्मक गारंटी का आश्वासन दिया funcहै कि यह एक नहीं प्राप्त होगा nullptrमें param

उस विषय पर ओपिनियन पीस। इस तरह से एक मामले में शुद्धता साबित करना मुश्किल है, बस गलती करना बहुत आसान है। तो संभावना मत लो, और हमेशा के लिए सूचक मापदंडों की जाँच करें nullptr। आप लंबे समय में कीड़े खोजने के लिए अपने आप को दर्द और पीड़ा और कड़ी मेहनत से बचाएंगे। और चेक की लागत के रूप में, यह गंदगी सस्ती है, और ऐसे मामलों में जहां संकलक में निर्मित स्थैतिक विश्लेषण इसे प्रबंधित कर सकता है, आशावादी इसे वैसे भी खत्म कर देगा। MSCC के लिए लिंक टाइम कोड जेनरेशन, या GCC के लिए WOPR (मुझे लगता है) चालू करें, और आप इसे प्रोग्राम वाइड प्राप्त करेंगे, अर्थात फ़ंक्शन कॉल में भी जो सोर्स कोड मॉड्यूल सीमा पार करते हैं।

दिन के अंत में उपरोक्त सभी बिंदुओं के संदर्भ को हमेशा प्राथमिकता देने के लिए एक बहुत ही ठोस मामला बनता है। वे सिर्फ चौतरफा सुरक्षित हैं।


3

दोनों तरफ इंट के साथ कास्ट पॉइंटर को निरंतर इंट को बनाएगा :

const int *ptr=&i;

या:

int const *ptr=&i;

constint के बाद निरंतर सूचक* बना देगा :

int *const ptr=&i;

इस स्थिति में, ये सभी निरंतर पूर्णांक के सूचक हैं , लेकिन इनमें से कोई भी निरंतर सूचक नहीं हैं:

 const int *ptr1=&i, *ptr2=&j;

इस स्थिति में सभी निरंतर पूर्णांक के लिए सूचक हैं और ptr2 निरंतर पूर्णांक के लिए सूचक है । लेकिन ptr1 निरंतर सूचक नहीं है:

int const *ptr1=&i, *const ptr2=&j;

3
  • अगर constहै बाईं ओर का *है, यह (मूल्य को दर्शाता है यह कोई फर्क नहीं पड़ता कि क्या यह है const intयाint const )
  • अगर constहै सही करने के लिए की* है, यह सूचक खुद को संदर्भित करता है
  • यह एक ही समय में दोनों हो सकता है

एक महत्वपूर्ण बिंदु: const int *p इसका मतलब यह नहीं है कि आप जिस मूल्य का उल्लेख कर रहे हैं वह निरंतर है !! । इसका मतलब है कि आप इसे उस पॉइंटर के माध्यम से नहीं बदल सकते (मतलब, आप $ * p = ... `) असाइन नहीं कर सकते। मान को अन्य तरीकों से बदला जा सकता है। उदाहरण के लिए

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

इसका मतलब ज्यादातर फ़ंक्शन हस्ताक्षर में उपयोग किया जाता है, यह गारंटी देने के लिए कि फ़ंक्शन गलती से पारित तर्कों को बदल नहीं सकता है।


2

सी के लिए पूर्णता की खातिर अन्य स्पष्टीकरणों के बाद, सी ++ के लिए निश्चित नहीं है।

  • पीपी - सूचक को सूचक
  • पी - सूचक
  • data - उदाहरण में बताई गई बात x
  • बोल्ड - केवल पढ़ने के लिए चर

सूचक

  • पी डेटा - int *p;
  • पी डेटा -int const *p;
  • पी डेटा -int * const p;
  • पी डेटा -int const * const p;

सूचक को इंगित करता है

  1. पीपी पी डेटा - int **pp;
  2. पीपी पी डेटा -int ** const pp;
  3. पीपी पी डेटा -int * const *pp;
  4. पीपी पी डेटा -int const **pp;
  5. पीपी पी डेटा -int * const * const pp;
  6. पीपी पी डेटा -int const ** const pp;
  7. पीपी पी डेटा -int const * const *pp;
  8. पीपी पी डेटा -int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

N-Dereference का स्तर

बस चलते रहो, लेकिन मानवता तुम्हें बहिष्कृत कर सकती है।

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

printf("%d \n", ****pppp);

0
  1. const int*- निरंतर intवस्तु को सूचक ।

आप सूचक का मान बदल सकते हैं; आप intऑब्जेक्ट का मान नहीं बदल सकते हैं , पॉइंटर इंगित करता है।


  1. const int * const- निरंतर सूचक को स्थिर intवस्तु।

आप पॉइंटर के मान को नहीं बदल सकते हैं और न ही पॉइंटर को intऑब्जेक्ट के मूल्य को इंगित करते हैं।


  1. int const *- निरंतर intवस्तु को सूचक ।

यह कथन 1 के बराबर है const int*- आप पॉइंटर के मान को बदल सकते हैं लेकिन आप intऑब्जेक्ट के मूल्य को नहीं बदल सकते हैं , पॉइंटर इंगित करता है।


वास्तव में, एक 4 वाँ विकल्प है:

  1. int * const- intवस्तु के लिए निरंतर सूचक ।

आप पॉइंटर पॉइंट के ऑब्जेक्ट का मान बदल सकते हैं लेकिन आप पॉइंटर के मूल्य को खुद नहीं बदल सकते। पॉइंटर हमेशा एक ही intऑब्जेक्ट को इंगित करेगा लेकिन इस ऑब्जेक्ट का यह मान intबदला जा सकता है।


यदि आप एक निश्चित प्रकार के C या C ++ निर्माण का निर्धारण करना चाहते हैं तो आप डेविड एंडरसन द्वारा बनाए गए दक्षिणावर्त / सर्पिल नियम का उपयोग कर सकते हैं ; लेकिन रॉस जे। एंडरसन द्वारा बनाए गए एंडरसन के नियम के साथ भ्रमित करने के लिए नहीं , जो कि कुछ अलग है।

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