सरणियों के साथ, ऐसा क्यों होता है कि [5] == 5 [a]?


1621

जैसा कि सी प्रोग्रामिंग भाषा (उर्फ: के एंड आर) में स्टैक ओवरफ्लो पॉडकास्ट # 34 में जोएल बताते हैं , सी में सरणियों की इस संपत्ति का उल्लेख है:a[5] == 5[a]

जोएल का कहना है कि यह सूचक अंकगणित के कारण है, लेकिन मुझे अभी भी समझ नहीं आया है। क्यों करता हैa[5] == 5[a] ?


48
कुछ ऐसा होगा [+] भी * (a ++) OR * (++ a) की तरह काम करता है?
एगॉन

45
@ ईगन: यह बहुत रचनात्मक है लेकिन दुर्भाग्य से यह नहीं है कि कंपाइलर कैसे काम करते हैं। संकलक a[1]टोकन की एक श्रृंखला के रूप में व्याख्या करता है, तार नहीं: * ({{पूर्णांक का स्थान {a संचालक} + {पूर्णांक} 1) * ({पूर्णांक} 1 {संचालक} + {पूर्णांक स्थान का}) के समान है।) लेकिन समान नहीं है * ({पूर्णांक स्थान} का {a संचालक} + {संचालक} +)
दिनाँह

11
इस पर एक दिलचस्प यौगिक बदलाव में चित्रित किया गया है विसंगत सरणी का उपयोग कर सकते हैं, जहां आप char bar[]; int foo[];और foo[i][bar]अभिव्यक्ति के रूप में प्रयोग किया जाता है।
जोनाथन लेफलर

5
@EldritchConundrum, आपको क्यों लगता है कि 'संकलक यह जाँच नहीं कर सकता कि बायाँ भाग एक पॉइंटर है'? हाँ यह कर सकते हैं। यह सच है कि a[b]= *(a + b)किसी दिए गए aऔर के लिए b, लेकिन यह +सभी प्रकार के लिए परिभाषित किए जाने के लिए भाषा डिजाइनरों की स्वतंत्र पसंद थी । i + pअनुमति देते समय कुछ भी उन्हें मना करने से नहीं रोक सकता था p + i
अच

13
@ ऑन्ड्रे वन आमतौर पर +कम्यूटेटिव होने की उम्मीद करता है, इसलिए हो सकता है कि असली समस्या एक अलग ऑफसेट ऑपरेटर को डिजाइन करने के बजाय पॉइंटर ऑपरेशंस को अंकगणित जैसा बनाना हो।
एल्ड्रिच कॉनन्ड्रम

जवाबों:


1924

सी मानक []ऑपरेटर को निम्नानुसार परिभाषित करता है:

a[b] == *(a + b)

इसलिए इसका a[5]मूल्यांकन करेंगे:

*(a + 5)

और इसका 5[a]मूल्यांकन करेगा:

*(5 + a)

aसरणी के पहले तत्व के लिए एक सूचक है। a[5]वह मान है जो 5 तत्वों से आगे है a, जो कि जैसा है *(a + 5), और प्राथमिक विद्यालय के गणित से हम जानते हैं कि वे समान हैं (इसके अलावा सराहनीय है )।


325
मुझे आश्चर्य है कि अगर यह अधिक नहीं है * ((5 * sizeof (a)) + a)। महान व्याख्या हालांकि।
जॉन मैकइंटायर

92
@ दीना: सी-कंपाइलर के नजरिए से, आप सही हैं। किसी भी आकार की आवश्यकता नहीं है और जिन भावों का मैंने उल्लेख किया है, वे समान हैं। हालांकि, मशीन कोड का निर्माण करते समय संकलक आकार को ध्यान में रखेगा। यदि एक अंतर सरणी है, a[5]तो mov eax, [ebx+20]इसके बजाय कुछ इस तरह संकलित करेगा[ebx+5]
मेहरदाद अफश्री

12
@ दीना: एक पता है, 0x1230 कहें। यदि एक 32-बिट इंट सरणी में था, तो एक [0] 0x1230 पर है, एक [1] 0x1234 पर है, एक [2] 0x1238 पर ... [a [5] x1244 आदि पर। यदि हम सिर्फ 5% पर हैं। 0x1230, हमें 0x1235 मिलता है, जो गलत है।
जेम्स कुर्रान

36
@ sr105: यह + ऑपरेटर के लिए एक विशेष मामला है, जहां एक ऑपरेंड एक पॉइंटर और दूसरा एक पूर्णांक है। मानक कहता है कि परिणाम सूचक के प्रकार का होगा। संकलक / पर्याप्त / स्मार्ट होना है।
ऐब

48
"प्राथमिक विद्यालय के गणित से हम जानते हैं कि उन लोगों के बराबर हैं" - मैं समझता हूँ कि आप सरल बना रहे हैं, लेकिन मैं जो लोग इस तरह है महसूस हो रहा है साथ हूँ से अधिक सरल बनाने। यह प्राथमिक नहीं है *(10 + (int *)13) != *((int *)10 + 13)। दूसरे शब्दों में, प्राथमिक विद्यालय अंकगणित की तुलना में यहाँ अधिक चल रहा है। कम्यूटेटर संकलक पर निर्भर करता है कि वह पहचानता है कि कौन सा ऑपरेंड एक पॉइंटर है (और किस आकार का ऑब्जेक्ट है)। इसे दूसरे तरीके से रखने के लिए (1 apple + 2 oranges) = (2 oranges + 1 apple), लेकिन (1 apple + 2 oranges) != (1 orange + 2 apples)
20

288

क्योंकि व्यूअर के संदर्भ में ऐरे एक्सेस को परिभाषित किया गया है। a[i]का अर्थ परिभाषित किया गया है *(a + i), जो प्रशंसनीय है।


42
एरे को पॉइंटर्स के संदर्भ में परिभाषित नहीं किया गया है, लेकिन उन तक पहुंच है।
को ऑर्बिट में लाइटनेस दौड़

5
मैं जोड़ूंगा "तो यह बराबर है *(i + a), जिसे लिखा जा सकता है i[a]"।
जिम बेल्टर

4
मेरा सुझाव है कि आप मानक से उद्धरण को शामिल करेंगे, जो निम्नानुसार है: 6.5.2.1: 2 एक पोस्टफिक्स अभिव्यक्ति के बाद वर्ग कोष्ठक में एक अभिव्यक्ति है [] एक सरणी वस्तु के एक तत्व का एक उपप्रकाशित पदनाम है। सबस्क्रिप्ट ऑपरेटर की परिभाषा [] है कि E1 [E2] (* (E1) + (E2)) के समान है। बाइनरी + ऑपरेटर पर लागू होने वाले रूपांतरण नियमों के कारण, यदि E1 एक सरणी ऑब्जेक्ट (समकक्ष, एक सरणी ऑब्जेक्ट के प्रारंभिक तत्व के लिए एक संकेतक) और E2 एक पूर्णांक है, तो E1 [E2] E2-th तत्व को नामित करता है E1 (शून्य से गिनती)।
21

अधिक सही होने के लिए: जब आप उन्हें एक्सेस करते हैं, तो संकेत में क्षय हो जाता है।
12431234123412341234123

नाइटपिक: यह कहने का कोई मतलब नहीं है कि " *(a + i)कम्यूटेटिव" है। हालांकि, *(a + i) = *(i + a) = i[a]क्योंकि इसके अलावा सराहनीय है।
एंड्रियास रिजेब्रैंड

231

मुझे लगता है कि दूसरे उत्तरों से कुछ छूट रहा है।

हां, p[i]परिभाषा के समतुल्य है *(p+i), जो (क्योंकि इसके अलावा कम्यूटेटिव है) बराबर है *(i+p), जो (फिर से, []ऑपरेटर की परिभाषा के अनुसार ) के बराबर है i[p]

(और array[i], सरणी नाम को संक्षेप में एक सूचक को सरणी के पहले तत्व में बदल दिया जाता है।)

लेकिन इसके अलावा इस मामले में स्पष्टता की स्पष्टता नहीं है।

जब दोनों ऑपरेंड एक ही प्रकार के होते हैं, या अलग-अलग न्यूमेरिक प्रकार के होते हैं, जिन्हें एक सामान्य प्रकार में बढ़ावा दिया जाता है, तो कम्यूटिविटी बहुत मायने रखती है x + y == y + x:।

लेकिन इस मामले में हम विशेष रूप से पॉइंटर अंकगणित के बारे में बात कर रहे हैं, जहां एक ऑपरेंड एक पॉइंटर है और दूसरा एक पूर्णांक है। (पूर्णांक + पूर्णांक एक अलग ऑपरेशन है, और सूचक + सूचक बकवास है।)

+ऑपरेटर के सी मानक विवरण ( N1570 6.5.6) कहते हैं:

इसके अलावा, या तो दोनों ऑपरेंड में अंकगणित प्रकार होंगे, या एक ऑपरेंड पूर्ण ऑब्जेक्ट प्रकार के लिए एक संकेतक होगा और दूसरे में पूर्णांक प्रकार होगा।

यह आसानी से कहा जा सकता है:

इसके अलावा, या तो दोनों ऑपरेंड में अंकगणित प्रकार होंगे, या बाएं ऑपरेंड एक पूर्ण ऑब्जेक्ट प्रकार के लिए एक संकेतक होगा और सही ऑपरेंड में पूर्णांक प्रकार होगा।

जिस स्थिति में दोनों i + pऔर i[p]अवैध होगा।

C ++ शब्दों में, हमारे पास वास्तव में ओवरलोड +ऑपरेटरों के दो सेट हैं , जिन्हें निम्न रूप से वर्णित किया जा सकता है:

pointer operator+(pointer p, integer i);

तथा

pointer operator+(integer i, pointer p);

जिनमें से केवल पहला वास्तव में आवश्यक है।

तो यह इस तरह से क्यों है?

C ++ को यह परिभाषा C से विरासत में मिली, जो इसे B से मिली (सरणी अनुक्रमण की कम्यूटिटी का स्पष्ट रूप से 1972 उपयोगकर्ताओं के संदर्भ B में उल्लेख किया गया है ), जो इसे BCPL (मैन्युअल दिनांक 1967) से मिला , जो इसे अच्छी तरह से प्राप्त कर सकता है। पहले की भाषाएँ (CPL? Algol?)।

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

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

और वर्षों में, उस नियम में कोई भी परिवर्तन मौजूदा कोड को तोड़ देता (हालांकि 1989 एएनएसआई सी मानक एक अच्छा अवसर हो सकता था)।

सी और / या सी ++ को बदलने के लिए बाईं ओर पॉइंटर लगाने की आवश्यकता होती है और दाएं पर पूर्णांक कुछ मौजूदा कोड को तोड़ सकता है, लेकिन वास्तविक अभिव्यंजक शक्ति का कोई नुकसान नहीं होगा।

तो अब हमारे पास arr[3]और 3[arr]बिल्कुल एक ही अर्थ है, हालांकि बाद वाला फॉर्म IOCCC के बाहर कभी दिखाई नहीं देना चाहिए ।


12
इस संपत्ति का शानदार विवरण। एक उच्च स्तर के दृष्टिकोण से, मुझे लगता 3[arr]है कि यह एक दिलचस्प कलाकृति है लेकिन कभी-कभी उपयोग किया जाना चाहिए। इस सवाल का स्वीकृत उत्तर (< stackoverflow.com/q/1390365/356> ) जो मैंने थोड़ी देर पहले पूछा था कि मैंने वाक्य रचना के बारे में सोचा है कि किस तरह से बदल गया है। यद्यपि इन चीजों को करने के लिए अक्सर तकनीकी रूप से सही और गलत तरीका नहीं होता है, फिर भी इस प्रकार की विशेषताएं आपको एक तरह से सोचने लगती हैं जो कार्यान्वयन विवरण से अलग होती हैं। इस अलग तरीके से सोचने पर लाभ होता है जो कि कार्यान्वयन के विवरणों को तय करने के दौरान खो जाता है।
दिनाह

3
जोड़-घटाव है। सी मानक के लिए इसे परिभाषित करने के लिए अन्यथा अजीब होगा। इसलिए यह आसानी से नहीं कहा जा सकता है "इसके अलावा, या तो दोनों ऑपरेंड में अंकगणित प्रकार होंगे, या बाएं ऑपरेंड पूर्ण ऑब्जेक्ट प्रकार के लिए एक संकेतक होगा और सही ऑपरेंड में पूर्णांक प्रकार होगा।" - इससे ज्यादातर लोगों को कोई मतलब नहीं होगा जो चीजें जोड़ते हैं।
इहानाई

9
@ जिहनी: जोड़ आमतौर पर सराहनीय है - और यह आमतौर पर एक ही प्रकार के दो ऑपरेंड लेता है। पॉइंटर जोड़ आपको पॉइंटर और पूर्णांक जोड़ने की सुविधा देता है, लेकिन दो पॉइंटर्स नहीं। IMHO कि पहले से ही एक बहुत ही विशेष रूप से अजीब मामला है जो पॉइंटर को बाएं ऑपरेंड की आवश्यकता है एक महत्वपूर्ण बोझ नहीं होगा। (कुछ भाषाओं में स्ट्रिंग संयोजन के लिए "+" का उपयोग होता है; यह निश्चित रूप से सराहनीय नहीं है।)
कीथ थॉम्पसन

3
@ सुपरकैट, यह और भी बुरा है। इसका मतलब होगा कि कभी-कभी x + 1! = 1 + x। यह पूरी तरह से जोड़ के सहयोगी संपत्ति का उल्लंघन करेगा।
इहानी

3
@ जिहानी: मुझे लगता है कि आपका मतलब कम्यूटेटिव प्रॉपर्टी से था; इसके अलावा पहले से ही सहयोगी नहीं है, क्योंकि अधिकांश कार्यान्वयन (1LL + 1U) -2! = 1LL + (1U-2) पर। वास्तव में, परिवर्तन कुछ स्थितियों को सहयोगी बना देगा जो वर्तमान में नहीं हैं, जैसे 3U + (UINT_MAX-2L) बराबर (3U + UINT_MAX) -2। हालांकि, सबसे अच्छी बात यह होगी कि भाषा के लिए प्रमोशनल पूर्णांक और "रैपिंग" बीजीय छल्लों के लिए नए अलग प्रकार जोड़ने के लिए है, ताकि ring16_t65535 धारण करने वाले 2 को जोड़ने पर ring16_tमूल्य 1, आकार के आकार केint साथ स्वतंत्र हो
सुपरकैट

196

और निश्चित रूप से

 ("ABCD"[2] == 2["ABCD"]) && (2["ABCD"] == 'C') && ("ABCD"[2] == 'C')

इसका मुख्य कारण यह था कि 70 के दशक में जब C को डिज़ाइन किया गया था, तो कंप्यूटर में बहुत मेमोरी नहीं थी (64KB बहुत थी), इसलिए C कंपाइलर ने बहुत अधिक वाक्यविन्यास जाँच नहीं की। इसलिए " X[Y]" बल्कि आँख बंद करके " *(X+Y)" में अनुवाद किया गया था

यह " +=" और " ++" वाक्यविन्यास भी समझाता है । " A = B + C" के रूप में सब कुछ एक ही संकलित रूप था। लेकिन, यदि बी ए के समान ऑब्जेक्ट था, तो एक विधानसभा स्तर का अनुकूलन उपलब्ध था। लेकिन कंपाइलर इसे पहचानने के लिए पर्याप्त उज्ज्वल नहीं था, इसलिए डेवलपर को ( A += C) था। इसी तरह, अगर Cथा 1, एक अलग विधानसभा स्तर अनुकूलन उपलब्ध था, और फिर डेवलपर यह स्पष्ट करने के लिए, क्योंकि संकलक यह नहीं पहचाना था। (हाल ही में कम्पाइलर करते हैं, इसलिए इन दिनों सिंटैक्स काफी हद तक अनावश्यक हैं)


127
असल में, वह असत्य का मूल्यांकन करता है; पहला शब्द "ABCD" [2] == 2 ["ABCD"] सत्य का मूल्यांकन करता है, या 1, और 1! = 'C': D
जोनाथन लेफ़लर

8
@ जोनाथन: एक ही अस्पष्टता इस पद के मूल शीर्षक के संपादन की ओर ले जाती है। क्या हम समान अंक गणितीय समकक्षता, कोड वाक्यविन्यास या छद्म कोड हैं। मैं गणितीय समानता का तर्क देता हूं लेकिन जब से हम कोड के बारे में बात कर रहे हैं, हम बच नहीं सकते हैं कि हम कोड सिंटैक्स के संदर्भ में सब कुछ देख रहे हैं।
दीना

19
क्या यह मिथक नहीं है? मेरा मतलब है कि कंपाइलर के लिए सरलीकृत करने के लिए + = और ++ ऑपरेटर बनाए गए थे? कुछ कोड उनके साथ स्पष्ट हो जाते हैं, और यह संकलक के लिए उपयोगी है, इससे कोई फर्क नहीं पड़ता कि संकलक इसके साथ क्या करता है।
थॉमस पैड्रॉन-मैककार्थी

6
+ = और ++ का एक और महत्वपूर्ण लाभ है। यदि बाएं हाथ की ओर मूल्यांकन के दौरान कुछ परिवर्तन होता है, तो परिवर्तन केवल एक बार किया जाएगा। a = a + ...; दो बार करेंगे।
जोहान्स स्काउब -

8
नहीं - "एबीसीडी" [2] == * ("एबीसीडी" + 2) = * ("सीडी") = 'सी'। एक स्ट्रिंग को Dereferencing करने से आपको एक विकल्प मिलता है, न कि एक विकल्प
MSalters

55

दीना की समस्या के बारे में एक बात का किसी ने उल्लेख नहीं किया है sizeof:

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


1
स्वीकृत उत्तर की टिप्पणियों में इस बारे में काफी विस्तृत बातचीत है। मैंने कहा कि मूल प्रश्न को संपादित करने में बातचीत का उल्लेख किया है, लेकिन आकार के अपने बहुत ही वैध चिंता को सीधे संबोधित नहीं किया है। यह सुनिश्चित करने के लिए नहीं कि एसओ में यह कैसे करना है। क्या मुझे मूल में एक और संपादन करना चाहिए। सवाल?
दीना

50

प्रश्न का उत्तर शाब्दिक रूप से देना। यह हमेशा सच नहीं होता हैx == x

double zero = 0.0;
double a[] = { 0,0,0,0,0, zero/zero}; // NaN
cout << (a[5] == 5[a] ? "true" : "false") << endl;

प्रिंट

false

27
वास्तव में एक "नैन" खुद के बराबर नहीं है: cout << (a[5] == a[5] ? "true" : "false") << endl;है false
ट्रू येल

8
@ उत्तर: उन्होंने कहा कि विशेष रूप से NaN मामले के लिए (और विशेष रूप से x == xहमेशा सच नहीं है)। मुझे लगता है कि यही उनका इरादा था। इसलिए वह तकनीकी रूप से सही है (और संभवतः, जैसा कि वे कहते हैं, सही का सबसे अच्छा प्रकार!)।
टिम Timस

3
प्रश्न C के बारे में है, आपका कोड C कोड नहीं है। वहाँ भी एक है NANमें <math.h>है, जो की तुलना में बेहतर है 0.0/0.0, क्योंकि 0.0/0.0यूबी है जब __STDC_IEC_559__निर्धारित नहीं है (अधिकांश कार्यान्वयनों परिभाषित नहीं करते __STDC_IEC_559__, लेकिन अधिकांश प्रयोगों पर 0.0/0.0अभी भी होगा काम)
12431234123412341234123

26

मुझे पता है कि यह बदसूरत सिंटैक्स "उपयोगी" हो सकता है, या कम से कम बहुत मजेदार हो सकता है जब आप एक अनुक्रमणिका के सरणी से निपटना चाहते हैं जो समान सरणी में स्थिति का उल्लेख करते हैं। यह नेस्टेड स्क्वायर ब्रैकेट्स को बदल सकता है और कोड को अधिक पठनीय बना सकता है!

int a[] = { 2 , 3 , 3 , 2 , 4 };
int s = sizeof a / sizeof *a;  //  s == 5

for(int i = 0 ; i < s ; ++i) {  

           cout << a[a[a[i]]] << endl;
           // ... is equivalent to ... 
           cout << i[a][a][a] << endl;  // but I prefer this one, it's easier to increase the level of indirection (without loop)

}

बेशक, मुझे पूरा यकीन है कि वास्तविक कोड में उस के लिए कोई उपयोग मामला नहीं है, लेकिन मुझे यह वैसे भी दिलचस्प लगा :)


जब आप देखते i[a][a][a]हैं कि आपको लगता है कि मैं एक सरणी के लिए एक सूचक या सरणी के लिए एक सरणी या एक सरणी के लिए एक संकेतक हूँ ... और aएक सूचकांक है। जब आप देखते हैं a[a[a[i]]], आपको लगता है कि एक सरणी या एक सरणी के लिए एक सूचक है और iएक सूचकांक है।
12431234123412341234123

1
वाह! यह इस "बेवकूफ" सुविधा का बहुत अच्छा उपयोग है। कुछ समस्याओं में एल्गोरिथम प्रतियोगिता में उपयोगी हो सकता है))
सर्ज ब्रेउसोव

26

अच्छा सवाल / जवाब।

बस यह इंगित करना चाहते हैं कि सी पॉइंटर्स और सरणियां समान नहीं हैं , हालांकि इस मामले में अंतर आवश्यक नहीं है।

निम्नलिखित घोषणाओं पर विचार करें:

int a[10];
int* p = a;

में a.out, प्रतीक aएक पते पर है जो सरणी की शुरुआत है, और प्रतीक pउस पते पर है जहां एक सूचक संग्रहीत किया जाता है, और उस स्मृति स्थान पर सूचक का मान सरणी की शुरुआत है।


2
नहीं, तकनीकी रूप से वे समान नहीं हैं। यदि आप कुछ b को int * const के रूप में परिभाषित करते हैं और इसे एक सरणी के लिए इंगित करते हैं, तो यह अभी भी एक संकेतक है, जिसका अर्थ है कि प्रतीक तालिका में, b एक मेमोरी स्थान को संदर्भित करता है जो एक पते को संग्रहीत करता है, जो बदले में सरणी को इंगित करता है। ।
पॉलिटिंकर

4
बहुत अच्छी बात है। मुझे याद है कि जब मैंने एक मॉड्यूल में चार प्रतीक के रूप में एक वैश्विक प्रतीक को परिभाषित किया था, तो यह बहुत बुरा बग था, इसे बाहरी रूप से * s घोषित करें; एक और मॉड्यूल में। यह सब एक साथ जोड़ने के बाद कार्यक्रम ने बहुत अजीब व्यवहार किया। क्योंकि एक्सटर्नल डिक्लेरेशन का उपयोग करने वाला मॉड्यूल आरओ को पॉइंटर के रूप में एरे के शुरुआती बाइट्स का उपयोग कर रहा था।
जियोर्जियो

1
मूल रूप से, C के दादा-दादी BCPL में, एक सरणी एक सूचक था। यही है, जब आपने लिखा था तो आपको जो मिला था (मैंने सी से अनुवाद किया है) int a[10]एक पॉइंटर था जिसे 'ए' कहा जाता था, जो 10 पूर्णांकों के लिए पर्याप्त स्टोर की ओर इशारा करता था। इस प्रकार एक + i और j + i का एक ही रूप था: स्मृति स्थानों के एक जोड़े की सामग्री जोड़ें। वास्तव में, मुझे लगता है कि बीसीपीएल टाइपहीन था, इसलिए वे समान थे। और आकार-प्रकार स्केलिंग लागू नहीं हुआ, क्योंकि BCPL विशुद्ध रूप से शब्द-उन्मुख (शब्द-संबोधित मशीनों पर भी) था।
डेव

मुझे लगता है कि अंतर को समझने के लिए सबसे अच्छा तरीका तुलना करने के लिए है int*p = a;करने के लिए int b = 5; बाद में, "बी" और "5" दोनों पूर्णांक हैं में, लेकिन "बी", एक चर रहा है, जबकि "5" एक निश्चित मूल्य है। इसी तरह, "पी" और "ए" दोनों एक चरित्र के पते हैं, लेकिन "ए" एक निश्चित मूल्य है।
जेम्स कर्रन

20

सी में संकेत के लिए, हमारे पास है

a[5] == *(a + 5)

और भी

5[a] == *(5 + a)

इसलिए यह सच है कि a[5] == 5[a].


15

जवाब के लिए नहीं, सिर्फ विचार के लिए कुछ खाना। यदि क्लास में इंडेक्स / सबस्क्रिप्ट ऑपरेटर ओवरलोड है, तो अभिव्यक्ति 0[x]काम नहीं करेगी:

class Sub
{
public:
    int operator [](size_t nIndex)
    {
        return 0;
    }   
};

int main()
{
    Sub s;
    s[0];
    0[s]; // ERROR 
}

चूंकि हमारे पास इंट क्लास तक पहुंच नहीं है, इसलिए ऐसा नहीं किया जा सकता है:

class int
{
   int operator[](const Sub&);
};

2
class Sub { public: int operator[](size_t nIndex) const { return 0; } friend int operator[](size_t nIndex, const Sub& This) { return 0; } };
बेन Voigt

1
क्या आपने वास्तव में इसे संकलित करने की कोशिश की है? ऐसे परिचालकों के समूह हैं जिन्हें कक्षा के बाहर (यानी गैर-स्थैतिक कार्यों के रूप में) लागू नहीं किया जा सकता है!
अजय

3
उफ़, तुम सही हो। " operator[]बिल्कुल एक पैरामीटर के साथ एक गैर-स्थैतिक सदस्य फ़ंक्शन होगा।" मैं उस प्रतिबंध से परिचित था operator=, यह नहीं सोचा था कि यह लागू होता है []
बेन वोइग्ट

1
बेशक, यदि आप []ऑपरेटर की परिभाषा बदलते हैं, तो यह फिर से बराबर नहीं होगा ... यदि a[b]आप इसके बराबर हैं *(a + b)और आप इसे बदलते हैं, तो आपको भी ओवरलोड करना होगा int::operator[](const Sub&);और intवर्ग नहीं है ...
लुइस कोलोराडो

7
यह ... नहीं है ... सी।
एमडी एक्सएफ

11

टेड जेन्सेन द्वारा A TUTORIAL ON POINTERS AND ARRAYS IN C में इसकी बहुत अच्छी व्याख्या है ।

टेड जेन्सेन ने इसकी व्याख्या की:

वास्तव में, यह सच है, यानी जहां भी कोई लिखता है a[i]उसे *(a + i) बिना किसी समस्या के बदला जा सकता है। वास्तव में, कंपाइलर दोनों ही मामलों में एक ही कोड बनाएगा। इस प्रकार हम देखते हैं कि सूचक अंकगणित सरणी अनुक्रमण के समान है। या तो वाक्य रचना एक ही परिणाम पैदा करता है।

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

अब, इस अंतिम अभिव्यक्ति को देखते हुए, इसका हिस्सा .. (a + i), ऑपरेटर और सी राज्य के नियमों का उपयोग करते हुए एक सरल जोड़ है कि इस तरह की अभिव्यक्ति प्रशंसनीय है। वह (a + i) समान है (i + a)। इस प्रकार हम *(i + a)बस के रूप में आसानी से लिख सकते हैं *(a + i)। लेकिन *(i + a)से आ सकता है i[a]! इस सब से यह जिज्ञासु सत्य सामने आता है कि यदि:

char a[20];

लिख रहे हैं

a[3] = 'x';

लेखन के समान ही है

3[a] = 'x';

4
a + i सरल जोड़ नहीं है, क्योंकि यह सूचक अंकगणित है। यदि तत्व का आकार 1 (चार) है, तो हाँ, यह पूर्णांक + जैसा है। लेकिन अगर यह पूर्णांक है (उदाहरण के लिए), तो यह + 4 * i के बराबर हो सकता है।
एलेक्स ब्राउन

@AlexBrown हाँ, यह सूचक अंकगणितीय है, यही कारण है कि आपका अंतिम वाक्य गलत है, जब तक कि आपने पहली बार 'ए' (चार *) होने का अनुमान नहीं लगाया (यह मानते हुए कि एक इंट 4 वर्ण है)। मुझे वास्तव में समझ में नहीं आता है कि इतने सारे लोग सूचक अंकगणित के वास्तविक मूल्य परिणाम पर क्यों लटकाए जा रहे हैं। सूचक अंकगणित का पूरा उद्देश्य अंतर्निहित सूचक मूल्यों को अलग करना है और प्रोग्रामर को पता मानों के बजाय ऑब्जेक्ट्स के हेरफेर के बारे में सोचने देना है।
jschultz410

8

मुझे पता है कि प्रश्न का उत्तर दिया गया है, लेकिन मैं इस स्पष्टीकरण को साझा करने का विरोध नहीं कर सकता।

मुझे कंपाइलर डिज़ाइन के सिद्धांत याद हैं, चलो मान लेते हैं aकि एक intसरणी है और int2 बाइट्स का आकार है, और a1000 के लिए आधार पता है।

कैसे a[5]काम करेगा ->

Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

इसलिए,

इसी तरह जब सी-कोड 3-एड्रेस कोड में टूट जाता है, 5[a]तो -> बन जाएगा

Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010 

तो मूल रूप से दोनों कथनों, स्मृति में है और इसलिए एक ही स्थान पर ओर इशारा करते हैं a[5] = 5[a]

यह स्पष्टीकरण भी कारण है कि सरणियों में नकारात्मक सूचकांक सी में काम क्यों करते हैं।

यानी अगर मैं पहुंच a[-5]गया तो वह मुझे दे देगा

Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

यह मुझे 990 स्थान पर ऑब्जेक्ट लौटाएगा।


6

में सी सरणियों , arr[3]और 3[arr]एक ही हैं, और उनके बराबर सूचक अंकन कर रहे हैं *(arr + 3)करने के लिए *(3 + arr)। लेकिन इसके विपरीत पर [arr]3या [3]arrसही रूप में नहीं है और सिंटेक्स त्रुटि में परिणाम होगा, (arr + 3)*और (3 + arr)*वैध भाव नहीं हैं। इसका कारण है डिरेक्शन ऑपरेटर को एक्सप्रेशन द्वारा दिए गए एड्रेस से पहले रखा जाना चाहिए, न कि एड्रेस के बाद।


6

सी संकलक में

a[i]
i[a]
*(a+i)

एक सरणी में एक तत्व को संदर्भित करने के विभिन्न तरीके हैं! (सभी वजन पर नहीं)


5

अब थोड़ा इतिहास। अन्य भाषाओं में, C के शुरुआती विकास पर BCPL का काफी प्रभाव था। यदि आपने BCPL में कुछ के साथ एक सरणी घोषित की है:

let V = vec 10

यह वास्तव में स्मृति के 11 शब्दों को आवंटित करता है, न कि 10. आमतौर पर V पहला था, और इसमें तुरंत निम्नलिखित शब्द का पता था। इसलिए सी के विपरीत, नामकरण वी उस स्थान पर गया और सरणी के शून्य तत्व का पता उठाया। इसलिए BCPL में सरणी अप्रत्यक्ष रूप में व्यक्त की गई है

let J = V!5

वास्तव में करना था J = !(V + 5)(BCPL वाक्यविन्यास का उपयोग करके) क्योंकि यह सरणी का आधार पता प्राप्त करने के लिए V लाने के लिए आवश्यक था। इस प्रकार V!5और 5!Vपर्यायवाची थे। एक वास्तविक अवलोकन के रूप में, WAFL (वार्विक फंक्शनल लैंग्वेज) BCPL में लिखा गया था, और मेरी मेमोरी के सर्वश्रेष्ठ को डेटा स्टोरेज के रूप में उपयोग किए गए नोड्स तक पहुंचने के लिए पूर्व के बजाय सिंटैक्स का उपयोग करने की प्रवृत्ति थी। दी यह कहीं से 35 और 40 साल पहले के बीच है, इसलिए मेरी याददाश्त थोड़ी कठोर है। :)

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

ध्यान दें कि !BCPL में एक अप्रत्यक्ष उपसर्ग ऑपरेटर और एक द्विआधारी infix ऑपरेटर दोनों अप्रत्यक्ष कर रहे थे। बस यह है कि द्विआधारी रूप में अप्रत्यक्ष करने से पहले दो ऑपरेंड को शामिल किया गया था। BCPL (और B) के शब्द उन्मुख स्वभाव को देखते हुए यह वास्तव में बहुत मायने रखता है। "पॉइंटर और पूर्णांक" का प्रतिबंध सी में आवश्यक बना दिया गया था जब यह डेटा प्रकार प्राप्त करता था, और sizeofएक चीज बन गया।


1

खैर, यह एक ऐसी सुविधा है जो भाषा समर्थन के कारण ही संभव है।

संकलक के a[i]रूप में व्याख्या करता है *(a+i)और अभिव्यक्ति का 5[a]मूल्यांकन करता है *(5+a)। चूंकि इसके अलावा यह कम्यूटेटिव है कि दोनों समान हैं। इसलिए अभिव्यक्ति का मूल्यांकन करता है true


यद्यपि यह निरर्थक है, स्पष्ट, संक्षिप्त और संक्षिप्त है।
बिल के

0

सी में

 int a[]={10,20,30,40,50};
 int *p=a;
 printf("%d\n",*p++);//output will be 10
 printf("%d\n",*a++);//will give an error

सूचक "चर" है

सरणी नाम एक "mnemonic" या "पर्यायवाची" है

p++;वैध है लेकिन a++अमान्य है

a[2] 2 [ए] के बराबर है क्योंकि इस दोनों पर आंतरिक ऑपरेशन है

"सूचक अंकगणित" आंतरिक रूप से गणना की जाती है

*(a+3) बराबरी *(3+a)


-4

सूचक प्रकार

1) सूचक डेटा के लिए

int *ptr;

2) डेटा के लिए कास्ट पॉइंटर

int const *ptr;

3) कास्ट पॉइंटर से कास्ट डेटा

int const *const ptr;

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

प्रमुख अंतर यह मैंने पाया है ...

हम एक पते से सूचक को फिर से शुरू कर सकते हैं लेकिन एक सरणी के साथ एक ही मामला नहीं।

======
और आपके प्रश्न पर वापस ...
a[5]कुछ भी नहीं है, लेकिन *(a + 5)
आप आसानी से समझ सकते हैं
a - जिसमें पता (लोग इसे आधार पते के रूप में कहते हैं) हमारी सूची में एक (2) प्रकार के सूचक की तरह
[]- वह ऑपरेटर हो सकता है सूचक के साथ बदली *

तो आखिरकार ...

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