2009-05-08 40 views
5

पेज पर। कश्मीर & आर के 109, हम देखते हैं:के एंड आर: वर्ण पॉइंटर्स की सरणी

void writelines(char *lineptr[], int nlines) 
{ 
    while (nlines -- > 0) printf("%s\n", *lineptr++); 
} 

मैं क्या * lineptr ++ बिल्कुल वही करती बारे में उलझन में हूँ। मेरी समझ से, printf को एक चार सूचक की आवश्यकता होती है, इसलिए हम उसे * lineptr प्रदान करते हैं। फिर हम सरणी में अगले चार सूचक तक लाइनप्टर बढ़ाते हैं? क्या यह अवैध नहीं है?

पृष्ठ 99 पर, के & आर लिखते हैं कि "एक सरणी नाम एक चर नहीं है; एक = pa [जहां एक सरणी है, pa एक सरणी के लिए सूचक है] और एक ++ अवैध हैं।"

उत्तर

4

एडम रोसेनफील्ड का चयनित उत्तर गलत है। कोबर्ड का जवाब भी। इसी कारण से मैंने दोनों उत्तरों को वोट दिया।

एडम मार्कोविट्ज़ *lineptr++ की व्याख्या सही है, लेकिन वह मुख्य सवाल यह है कि यह कानूनी C99 कोड है उत्तर नहीं देता। केवल टॉम भविष्य करता है; दुर्भाग्यवश वह *lineptr++ की व्याख्या नहीं करता है। मैंने उन्हें प्रत्येक बिंदु दिया।

तो छोटे के लिए, lineptr एक चर रहा है और सूचक के रूप में हेरफेर किया जा सकता। इस प्रकार सूचक को बढ़ाने के लिए कानूनी है।

lineptr वर्ण के दृश्यों की ओर इशारा के अनुक्रम में एक सूचक है। दूसरे शब्दों में यह एक स्ट्रिंग सरणी की पहली स्ट्रिंग के लिए एक सूचक है। कोड के मुताबिक हम मान सकते हैं कि स्ट्रिंग शून्य हैं ('\ 0') चार अनुक्रमों को समाप्त कर दिया गया है। nlines सरणी में तारों की संख्या है।

जबकि परीक्षण अभिव्यक्ति nlines-- > 0 है। nlines-- एक पोस्ट कमी है (क्योंकि -- चर के दाईं ओर है)। इस प्रकार को के बाद निष्पादित किया गया है परीक्षण परीक्षण किया गया है और परीक्षण परिणाम के बावजूद, किसी भी मामले में।

तो, यदि nlines तर्क के रूप में दिया गया मान 0 था, तो परीक्षण पहले किया जाता है और false देता है; लूप में निर्देश निष्पादित नहीं हैं। ध्यान दें कि जब nlines वैसे भी कम कर रहा है, while पाश के बाद nlines का मूल्य -1 हो जाएगा।

तो nlines == 1, परीक्षण true वापस आ जाएगी और nlines कम कर दिया जाएगा; लूप में निर्देश एक बार निष्पादित किया जाएगा। ध्यान दें कि इन निर्देशों को निष्पादित किया गया है जबकि nlines का मान 0 है। जब परीक्षण फिर से किया जाता है, तो हम nlines == 0 पर मामले में वापस आते हैं।

printf अनुदेश *lineptr++ अभिव्यक्ति का उपयोग करता है। यह पॉइंटर की एक पोस्ट वृद्धि है (++ चर के दाईं ओर है)। इसका अर्थ यह है कि अभिव्यक्ति का मूल्यांकन पहले किया जाता है और इसके उपयोग के उपयोग के बाद किया जाता है। तो पहले निष्पादन printf पर स्ट्रिंग सरणी के पहले तत्व की एक प्रति प्राप्त होती है, जो स्ट्रिंग के पहले चार में एक सूचक है। lineptr उसके बाद ही बढ़ी है। अगली बार printf को दूसरे तत्व पर lineptr अंक निष्पादित किया जाना है और दूसरी स्ट्रिंग मुद्रित होने पर तीसरे स्थान पर ले जाया जाएगा। यह समझ में आता है क्योंकि हम स्पष्ट रूप से पहली स्ट्रिंग मुद्रित करना चाहते हैं। यदि एडम रोसेनफील्ड सही था, तो पहली स्ट्रिंग को छोड़ दिया गया था और अंत में हम आखिरी एक स्ट्रिंग को प्रिंट करने का प्रयास करेंगे जो स्पष्ट रूप से करने के लिए एक बुरी चीज है।

तो, printf अनुदेश एक सामान्य नियम के रूप में, दो निम्नलिखित निर्देशों

printf("%s\n", *lineptr); 
++lineptr; // or lineptr++, which is equivalent but not as good. lineptr += 1; is ok too. 

नोट का एक संक्षिप्त रूप है, कि जब पूर्व और बाद के वेतन वृद्धि उनकी कार्रवाई में बराबर हैं, पूर्व प्रदर्शन कारणों के लिए वृद्धि बेहतर है। कंपाइलर्स आपके लिए इसे स्विच करने का ख्याल रखेंगे। वैसे, अधिकतर। जब भी संभव हो, प्री-ऑपरेटरों के लिए यह बेहतर होता है, इसलिए इसका हमेशा उपयोग होता है। एक बार जब आप एक पोस्ट लागू करते हैं और सी ++ में स्वयं को बढ़ाते हैं तो कारण अधिक स्पष्ट हो जाता है।

+0

स्पष्टीकरण के लिए धन्यवाद ... मैं सोच रहा था कि मैं पागल हो रहा था या नहीं :) –

6

lineptr वास्तव में एक सरणी नहीं है; यह एक सूचक के लिए एक सूचक है।

  1. lineptr सरणी में अगले तत्व को इंगित करने की संख्या बढ़ जाती है
  2. lineptr++ का परिणाम है: ध्यान दें कि postincrement ऑपरेटर ++ भिन्नता ऑपरेटर * की तुलना में अधिक पूर्वता है, तो यह है कि क्या lineptr++ में होता है lineptr के पुराने मूल्य, अर्थात् सरणी
  3. *lineptr++ dereferenced कि, यह सरणी में वर्तमान तत्व का मान है, इसलिए में वर्तमान तत्व के लिए सूचक

इस प्रकार, जबकि लूप lineptr (प्रत्येक तत्व char*) की ओर इशारा करते हुए सरणी के सभी तत्वों पर पुनरावृत्त करता है और उन्हें प्रिंट करता है।

+0

आह, यह समझ में आता है। मेरे प्रश्न का उत्तर देने के लिए सभी को धन्यवाद! –

5

यह निम्नलिखित के रूप में *lineptr++ की कल्पना करना आसान हो सकता है:

*(lineptr++) 

वहाँ, char* रों की सरणी के लिए सूचक, कि है, सरणी के अगले तत्व में ले जाया जाता lineptr[0] से, हम lineptr[1] पर जाएं। (सूचक की वेतन वृद्धि सूचक की पोस्टफ़िक्स वेतन वृद्धि की वजह से dereferencing के बाद होता है।)

तो बुनियादी तौर पर, निम्नलिखित बातें होती हैं:

  1. lineptr[0] (प्रकार char* का) deferencing द्वारा लिया गया है।
  2. पॉइंटर सरणी के अगले तत्व में वृद्धि हुई है। (सूचक lineptr पर पोस्टफिक्स वृद्धि द्वारा)
  3. सूचक अब lineptr[1] पर इंगित करता है, फिर से चरण 1 से प्रक्रिया को दोहराएं।
+0

मुझे लगता है कि * (lineptr ++) यहां बहुत उपयोगी नहीं है। इसका तात्पर्य है कि * रेफरर * पहले से ही * इसे संदर्भित किया गया है। वास्तव में क्या हो रहा है दो अलग-अलग कार्यों की तरह है: * lineptr, ++ lineptr। – Naaff

+0

यदि आप (* lineptr) ++ का उपयोग करते हैं तो आप dereference और फिर वृद्धि करेंगे। लाइनर एक सरणी के लिए पॉइंटर है जिसे आप पहली बार रेफरेंसिंग द्वारा चुनते हैं और फिर आप अगले चरित्र को इंगित करने के लिए पॉइंटर बढ़ाते हैं। तो यदि लाइन पॉइंटर 3 लाइनों की सरणी है तो आपकी ब्रैकेटिंग पहले, दूसरे और तीसरे चरित्र से पहली बार 3 बार प्रिंट करेगी। * (Lineptr ++) तीनों पंक्तियों में से प्रत्येक को प्रिंट करेगा। – stefanB

+0

* (लाइनप्टर ++) अभी भी एक कथन है, इसलिए पोस्टर वृद्धि होने से पहले पॉइंटर का डिफ्रेंसिंग घटित होगा। एक कोष्ठक जोड़ना केवल ऑपरेटर प्राथमिकता को बदलता है। इस मामले में, जैसा कि एडम रोसेनफील्ड के उत्तर से इंगित किया गया है, ++ की तुलना में ++ अधिक प्राथमिकता है, इसलिए ब्रांड्स केवल उस एकल कथन में होने वाली दो चीजों के दृश्य संकेत के रूप में कार्य करता है। – coobird

7

पढ़ना जारी रखें! पी के बहुत नीचे। 99

एक समारोह परिभाषा औपचारिक पैरामीटर के रूप में,

char s[]; 

और

char *s; 

बराबर हैं; हम बाद वाले को पसंद करते हैं क्योंकि यह अधिक स्पष्ट रूप से कहता है कि पैरामीटर एक सूचक है।

आईई। आप फ़ंक्शन में कभी भी एक सरणी (जो चर नहीं है) पास कर सकते हैं। यदि आप ऐसा फ़ंक्शन घोषित करते हैं जो ऐसा लगता है कि यह एक सरणी लेता है, तो यह वास्तव में एक पॉइंटर लेता है (जो एक चर) है। यह समझ में आता है। फ़ंक्शन तर्क के लिए यह एक अजीब नहीं होना चाहिए - हर बार जब आप फ़ंक्शन को कॉल करते हैं तो यह एक अलग मूल्य हो सकता है, इसलिए यह निश्चित रूप से स्थिर नहीं है!

+0

ठीक है, आप किसी फ़ंक्शन में सरणी नाम पास कर सकते हैं, दृश्य दृश्यों के पीछे कुछ ऐसा है जो ऐसा लगता है कि आप वास्तव में एक पॉइंटर में पारित हुए हैं। यह समझने की तुलना में मुकाबला करने की तरह लगता है। –

+0

ओह ठीक है, मुझे अब याद है। सरणी को फ़ंक्शन के स्टैक फ्रेम में कॉपी नहीं किया गया है, केवल उस सरणी के लिए एक पॉइंटर। याद दिलाने के लिए शुक्रिया! –