यहां एक विस्तृत विवरण दिया गया है, जो मुझे आशा है कि सहायक होगा। आइए अपने कार्यक्रम से शुरू करें, क्योंकि यह सबसे सरल है।
int main()
{
const char *p = "Hello";
while(*p++)
printf("%c",*p);
return 0;
}
पहला बयान:
const char* p = "Hello";
p
को सूचक के रूप में घोषित करता है char
। जब हम "पॉइंटर टू ए char
" कहते हैं , तो इसका क्या अर्थ है? इसका अर्थ है कि का मान p
एक का पता है char
; p
हमें बताता है कि स्मृति में कहां एक जगह रखने के लिए कुछ जगह है char
।
यह स्टेटमेंट p
स्ट्रिंग लिटरल में पहले कैरेक्टर की ओर इशारा करता है "Hello"
। इस अभ्यास के p
लिए, संपूर्ण स्ट्रिंग की ओर नहीं, बल्कि केवल पहले चरित्र की ओर इशारा करते हुए इसे समझना महत्वपूर्ण है 'H'
। आखिरकार, p
एक के लिए एक सूचक है char
, पूरे स्ट्रिंग के लिए नहीं। के मान का p
पता 'H'
है "Hello"
।
फिर आप एक लूप सेट करते हैं:
while (*p++)
लूप स्थिति का क्या *p++
अर्थ है? यहां तीन चीजें काम कर रही हैं, जो इस puzzling को बनाती हैं (कम से कम जब तक परिचित सेट नहीं करते हैं):
- दो संचालकों की पूर्ववर्ती स्थिति, उपसर्ग
++
और अप्रत्यक्ष*
- पोस्टफ़िक्स इंक्रीमेंट एक्सप्रेशन का मान
- पोस्टफिक्स इंक्रीमेंट एक्सप्रेशन का साइड इफेक्ट
1. पूर्वधारणा । ऑपरेटरों के लिए पूर्ववर्ती तालिका पर एक त्वरित नज़र आपको बताएगी कि पोस्टफिक्स इन्क्रीमेंट में डीरेफेरेंस / इनडायरेक्शन (15) की तुलना में अधिक पूर्वता (16) है। इसका मतलब है कि जटिल अभिव्यक्ति *p++
जा रहा है के रूप में वर्गीकृत किया जा करने के लिए: *(p++)
। यह कहना है, *
भाग के मूल्य पर लागू किया जाएगा p++
। तो p++
पहले भाग लेते हैं ।
2. उपसर्ग अभिव्यक्ति मूल्य । मूल्य वृद्धिp++
के p
पहले का मूल्य है । यदि आपके पास है:
int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);
उत्पादन होगा:
7
8
क्योंकि वेतन वृद्धि i++
से i
पहले मूल्यांकन करता है । इसी तरह p++
वर्तमान मूल्य का मूल्यांकन करने जा रहा है p
। जैसा कि हम जानते हैं कि वर्तमान मूल्य का p
पता है 'H'
।
तो अब के p++
भाग का *p++
मूल्यांकन किया गया है; इसका वर्तमान मूल्य है p
। तब *
भाग होता है। *(current value of p)
का अर्थ है: द्वारा आयोजित पते पर मूल्य का उपयोग p
। हम जानते हैं कि उस पते पर मूल्य है 'H'
। तो अभिव्यक्ति का *p++
मूल्यांकन करता है 'H'
।
अब एक मिनट रुकिए, आप कह रहे हैं। यदि *p++
मूल्यांकन किया जाता है 'H'
, 'H'
तो उपरोक्त कोड में प्रिंट क्यों नहीं होता है ? यहीं से साइड इफेक्ट सामने आते हैं।
3. उपसर्ग अभिव्यक्ति साइड इफेक्ट । पोस्टफिक्स ++
में वर्तमान ऑपरेंड का मूल्य होता है, लेकिन इसका उस ऑपरेंड को बढ़ाने का साइड इफेक्ट होता है। है ना? उस int
कोड को फिर से देखें:
int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);
जैसा कि पहले उल्लेख किया गया है, उत्पादन होगा:
7
8
जब i++
पहले में मूल्यांकन किया जाता है printf()
, तो यह 7 का मूल्यांकन करता है। लेकिन सी मानक की गारंटी देता है कि दूसरे बिंदु पर अमलprintf()
शुरू होने से पहले कुछ बिंदु पर , ऑपरेटर का दुष्प्रभाव हुआ++
होगा। यह कहना है, दूसरे के printf()
होने से पहले, पहले i
में ++
ऑपरेटर के परिणामस्वरूप वृद्धि हुई होगी printf()
। यह, वैसे, कुछ गारंटी में से एक है जो मानक साइड इफेक्ट के समय के बारे में देता है।
आपके कोड में, तब, जब अभिव्यक्ति *p++
का मूल्यांकन किया जाता है, तो इसका मूल्यांकन होता है 'H'
। लेकिन जब तक आप इसे प्राप्त करते हैं:
printf ("%c", *p)
कि pesky पक्ष प्रभाव हुआ है। p
बढ़ा दिया गया है। वाह! यह अब इंगित नहीं करता है 'H'
, लेकिन पिछले एक चरित्र को 'H'
: 'e'
दूसरे शब्दों में। जो आपके कॉकटनीफाइड आउटपुट की व्याख्या करता है:
ello
इसलिए अन्य उत्तरों में सहायक (और सटीक) सुझावों का कोरस: प्राप्त उच्चारण को प्रिंट करने के लिए "Hello"
और उसके कॉकटनी समकक्ष के लिए नहीं, आपको कुछ इस तरह की आवश्यकता है
while (*p)
printf ("%c", *p++);
उस के लिए बहुत। बाकी के बारे में क्या? आप इनका अर्थ पूछते हैं:
*ptr++
*++ptr
++*ptr
हमने अभी पहले के बारे में बात की है, तो चलो दूसरे को देखें *++ptr
:।
हमने अपने पहले स्पष्टीकरण में देखा था कि पोस्टफ़िक्स इन्क्रीमेंट p++
की एक निश्चित पूर्वता , एक मूल्य और एक साइड इफेक्ट है । उपसर्ग वृद्धि ++p
में इसके उपसर्ग प्रतिपक्ष के समान दुष्प्रभाव होते हैं : यह 1 से अपने ऑपरेंड को बढ़ाता है। हालांकि, इसकी एक अलग पूर्ववर्तीता और एक अलग मूल्य है ।
उपसर्ग वृद्धि में उपसर्ग की तुलना में कम पूर्वता है; इसकी पूर्वता है। 15. दूसरे शब्दों में, इसकी पूर्वता / अप्रत्यक्ष परिचालक के रूप में एक ही पूर्वता है *
। जैसी अभिव्यक्ति में
*++ptr
क्या मामलों की पूर्ववर्तीता नहीं है: दो ऑपरेटर पूर्वता में समान हैं। तो संबद्धता किक में। उपसर्ग वेतन वृद्धि और अविवेक ऑपरेटर सही-बाएँ संबद्धता है। उस अनुरूपता के ptr
कारण , ऑपरेटर को ऑपरेटर ++
से पहले बाएं से अधिक ऑपरेटर के साथ समूहीकृत किया जा रहा है *
। दूसरे शब्दों में, अभिव्यक्ति समूहीकृत होने जा रही है *(++ptr)
। तो, जैसा कि *ptr++
लेकिन एक अलग कारण के लिए, यहाँ भी *
भाग के मूल्य पर लागू होने जा रहा है ++ptr
।
तो वह मूल्य क्या है? उपसर्ग वृद्धिशील अभिव्यक्ति का मूल्य वृद्धि के बाद ऑपरेंड का मूल्य है । यह इसे पोस्टफिक्स इंक्रीमेंट ऑपरेटर से बहुत अलग जानवर बनाता है। मान लीजिए कि आपके पास है:
int i = 7;
printf ("%d\n", ++i);
printf ("%d\n", i);
उत्पादन होगा:
8
8
... जो हमने पोस्टफिक्स ऑपरेटर के साथ देखा उससे अलग। इसी प्रकार, यदि आपके पास:
const char* p = "Hello";
printf ("%c ", *p); // note space in format string
printf ("%c ", *++p); // value of ++p is p after the increment
printf ("%c ", *p++); // value of p++ is p before the increment
printf ("%c ", *p); // value of p has been incremented as a side effect of p++
उत्पादन होगा:
H e e l // good dog
क्या आप देखते हैं क्यों?
अब हम तीसरी अभिव्यक्ति के बारे में पूछते हैं ++*ptr
। वास्तव में, यह बहुत मुश्किल है। दोनों ऑपरेटरों में एक ही पूर्वता है, और दाएं-बाएं सहानुभूति है। इसका मतलब है कि अभिव्यक्ति को समूहीकृत किया जाएगा ++(*ptr)
। ++
भाग के मूल्य को लागू किया जाएगा *ptr
हिस्सा।
तो अगर हमारे पास है:
char q[] = "Hello";
char* p = q;
printf ("%c", ++*p);
आश्चर्यजनक रूप से अहंकारी उत्पादन होने जा रहा है:
I
क्या?! ठीक है, इसलिए *p
भाग का मूल्यांकन करने जा रहा है 'H'
। फिर ++
खेलने में आता है, किस बिंदु पर, यह 'H'
सूचक पर लागू होने वाला है , बिल्कुल नहीं! जब आप 1 को जोड़ते हैं तो क्या होता है 'H'
? आपको 'H'
72 का ASCII मूल्य 1 प्लस मिलता है ; आपको 73 मिलते हैं। एक के रूप में प्रतिनिधि char
, और आप char
73 के ASCII मूल्य के साथ प्राप्त करते हैं 'I'
:।
आपके प्रश्न में आपके द्वारा पूछे गए तीन भावों का ध्यान रखता है। यहाँ एक और है, जो आपके प्रश्न के लिए पहली टिप्पणी में उल्लिखित है:
(*ptr)++
वह भी दिलचस्प है। यदि आपके पास है:
char q[] = "Hello";
char* p = q;
printf ("%c", (*p)++);
printf ("%c\n", *p);
यह आपको यह उत्साही आउटपुट देगा:
HI
क्या चल रहा है? फिर, यह पूर्वता , अभिव्यक्ति मूल्य और दुष्प्रभावों की बात है । कोष्ठक के कारण, *p
भाग को प्राथमिक अभिव्यक्ति के रूप में माना जाता है। प्राथमिक अभिव्यक्तियाँ बाकी सब कुछ ट्रम्प; पहले उनका मूल्यांकन किया जाता है। और *p
, जैसा कि आप जानते हैं, मूल्यांकन करता है 'H'
। शेष अभिव्यक्ति, ++
हिस्सा, उस मूल्य पर लागू होता है। तो, इस मामले में, (*p)++
बन जाता है 'H'++
।
का मूल्य क्या है 'H'++
? यदि आपने कहा है 'I'
, तो आप पोस्टफ़ेयर इन्क्रीमेंट के साथ मूल्य बनाम साइड इफेक्ट की हमारी चर्चा (पहले से ही) भूल चुके हैं। याद रखें, 'H'++
के वर्तमान मूल्य का मूल्यांकन करता है'H'
। ताकि पहले printf()
प्रिंट हो जाए 'H'
। फिर, एक साइड इफेक्ट के रूप में , कि 'H'
वृद्धि होने जा रही है 'I'
। दूसरा printf()
प्रिंट कि 'I'
। और आपका जयकारे लगा रहे हैं।
सब ठीक है, लेकिन उन आखिरी दो मामलों में, मुझे क्यों ज़रूरत है
char q[] = "Hello";
char* p = q;
मैं ऐसा क्यों नहीं कर सकता
/*const*/ char* p = "Hello";
printf ("%c", ++*p); // attempting to change string literal!
क्योंकि "Hello"
एक स्ट्रिंग शाब्दिक है। यदि आप कोशिश करते हैं ++*p
, तो आप 'H'
स्ट्रिंग को बदलने की कोशिश कर रहे हैं 'I'
, पूरे स्ट्रिंग को बना रहे हैं "Iello"
। सी में, स्ट्रिंग शाब्दिक केवल-पढ़ने के लिए हैं; उन्हें संशोधित करने का प्रयास अपरिभाषित व्यवहार को आमंत्रित करता है। "Iello"
के रूप में अच्छी तरह से अंग्रेजी में अपरिभाषित है, लेकिन यह सिर्फ संयोग है।
इसके विपरीत, आपके पास नहीं हो सकता
char p[] = "Hello";
printf ("%c", *++p); // attempting to modify value of array identifier!
क्यों नहीं? क्योंकि इस उदाहरण में, p
एक सरणी है। एक सरणी एक परिवर्तनीय एल-मूल्य नहीं है; आप p
पूर्व या बाद के वेतन वृद्धि या वेतन वृद्धि के बिंदुओं को नहीं बदल सकते , क्योंकि सरणी का नाम वैसे ही काम करता है जैसे कि यह एक निरंतर सूचक है। (यह वास्तव में ऐसा नहीं है; यह देखने के लिए सिर्फ एक सुविधाजनक तरीका है।)
योग करने के लिए, यहां उन तीन चीजों के बारे में बताया गया है:
*ptr++ // effectively dereferences the pointer, then increments the pointer
*++ptr // effectively increments the pointer, then dereferences the pointer
++*ptr // effectively dereferences the pointer, then increments dereferenced value
और यहाँ एक चौथाई है, हर बिट अन्य तीन की तरह मज़ेदार है:
(*ptr)++ // effectively forces a dereference, then increments dereferenced value
यदि ptr
वास्तव में एक सरणी पहचानकर्ता है तो पहला और दूसरा दुर्घटनाग्रस्त हो जाएगा । तीसरा और चौथा दुर्घटनाग्रस्त होगा अगर ptr
एक स्ट्रिंग शाब्दिक को इंगित करता है।
ये लो। मुझे उम्मीद है कि अब यह सब क्रिस्टल है। आप एक महान दर्शक रहे हैं, और मैं पूरे सप्ताह यहां रहूंगा।
(*ptr)++
(से*ptr++