2012-01-18 7 views
20

मैं कई सालों से प्रोग्रामिंग सी/सी ++ रहा हूं, लेकिन आजकल आकस्मिक खोज ने मुझे कुछ हद तक उत्सुक बना दिया ... दोनों आउटपुट एक ही परिणाम को नीचे दिए गए कोड में क्यों उत्पन्न करते हैं? (arr, arr[0] का पता ज़ाहिर है arr[0] के लिए सूचक यानी मैं &arr उम्मीद है कि सूचक की पता होना करने के लिए होगा, लेकिन यह arr रूप में एक ही मूल्य है।)एआर और एआरआर क्यों समान है?

int arr[3]; 
    cout << arr << endl; 
    cout << &arr << endl; 

टिप्पणी: इस सवाल था बंद, लेकिन अब यह फिर से खोला गया है। (धन्यवाद?)

मुझे पता है कि &arr[0] और arr एक ही नंबर के लिए मूल्यांकन करता है, लेकिन यह है कि मेरे सवाल नहीं है! सवाल यह है कि &arr और arr उसी संख्या का मूल्यांकन क्यों करता है। यदि arr एक शाब्दिक है (किसी भीवेयर को संग्रहीत नहीं किया गया है), तो संकलक को शिकायत करनी चाहिए और कहें कि arr एक लाभा नहीं है। यदि arr का पता कहीं भी संग्रहीत किया गया है तो &arr मुझे उस स्थान का पता देना चाहिए। (लेकिन यह मामला नहीं है)

अगर मैं लिखना

स्थिरांक पूर्णांक * arr2 = आगमन;

तो किसी भी पूर्णांक i के लिए arr2[i]==arr[i], लेकिन ।

+0

"उस सूचक का पता" का क्या अर्थ है? सूचक एक चर में संग्रहित नहीं है। –

+1

@ डेविड श्वार्टज़, अगर मैंने int * arr2 = new int [3] लिखा था, तो और arr2 एक चर में संग्रहीत किया गया होगा। शायद सर एक शाब्दिक स्थिर है? लेकिन अगर कोई स्थिर (उदा। और 123) का पता लेता है तो संकलक शिकायत करता है (123 एक लालसा नहीं है)। जब मैंने एआर का पता लिया तो संकलक शिकायत नहीं करता था। – ragnarius

+6

मुझे नहीं लगता कि यह एक डुप्लिकेट है! – ragnarius

उत्तर

13

वे समान नहीं हैं। वे सिर्फ एक ही स्मृति स्थान पर हैं। उदाहरण के लिए, arr[2] का पता प्राप्त करने के लिए आप arr+2 लिख सकते हैं, लेकिन ऐसा करने के लिए (&arr)+2 नहीं।

इसके अलावा, sizeof arr और sizeof &arr अलग हैं।

+4

यह ध्यान रखना अच्छा है कि '(& arr) + 2' संकलित होगा, और यहां तक ​​कि यहां तक ​​कि चलाया जा सकता है, लेकिन यह अपरिभाषित व्यवहार है, और _not_ आपको' arr [2] 'दे देगा। –

+0

यह यहां संकलित नहीं होगा! प्रारंभिकरण में 'int (*) [3]' to 'int *' को परिवर्तित नहीं किया जा सकता है –

+1

'int (*) [3]' एक int में कनवर्ट करने योग्य है '** ** एक सूचक को एक सूचक को एक सूचक में कनवर्ट करने योग्य है एक सूचक –

5

पता एक ही है लेकिन दोनों अभिव्यक्ति अलग हैं। वे बस एक ही स्मृति स्थान पर शुरू करते हैं। दोनों अभिव्यक्तियों के प्रकार अलग हैं।

arr का मान प्रकार int * की है और &arr का मान प्रकार int (*)[3] की है।

& पता ऑपरेटर है और किसी ऑब्जेक्ट का पता उस ऑब्जेक्ट का सूचक है। int [3] प्रकार की ऑब्जेक्ट का सूचक प्रकार int (*)[3]

+0

जैसा होता है, सरणी का पता स्वयं और उसके पहले तत्व का पता संख्यात्मक रूप से समान होता है। लेकिन उनके पास विभिन्न प्रकार हैं और अन्य मामलों में अलग-अलग व्यवहार करते हैं। –

+0

'arr' का मान 'int (&) [3]' प्रकार का है जो 'int *' को" प्रचारित "हो जाता है क्योंकि 'cout' में सरणी के लिए अधिभार नहीं होता है। –

17
#include <cassert> 

struct foo { 
    int x; 
    int y; 
}; 

int main() {  
    foo f; 
    void* a = &f.x; 
    void* b = &f; 
    assert(a == b); 
} 

इसी कारण दो पते a और bare the same ऊपर। किसी ऑब्जेक्ट का पता उसके पहले सदस्य के पते जैसा ही है (हालांकि उनके प्रकार अलग हैं)।

      arr 
         _______^_______ 
        /    \ 
        | [0] [1] [2] | 
--------------------+-----+-----+-----+-------------------------- 
     some memory |  |  |  |  more memory 
--------------------+-----+-----+-----+-------------------------- 
        ^
        | 
      the pointers point here 

आप इस चित्र में देख सकते हैं, सरणी के पहले तत्व सरणी खुद के रूप में एक ही पते पर है।

+0

मैंने कोशिश की, लेकिन f.x! = और f.y। तो किसी ऑब्जेक्ट का पता केवल अपने पहले सदस्य के पते जैसा ही है ... – ragnarius

+1

@ धनुष: सरणी का पता सरणी के पहले तत्व के पते के समान है। तत्वों के सदस्यों के साथ कुछ लेना देना नहीं है। –

+0

@ धनुष: यही वही है जो मैंने कहा था। –

6

दोनों के समान मूल्य हैं लेकिन विभिन्न प्रकार हैं।

जब यह (& या sizeof के संकार्य नहीं) अपने आप में प्रयोग किया जाता है, arr एक सूचक को int को सरणी में पहले int का पता पकड़े मूल्यांकन करता है। &arr सरणी के पते को पकड़े हुए तीन int एस के सरणी के लिए एक सूचक को मूल्यांकन करता है। चूंकि सरणी में पहले int सरणी की शुरुआत में होना चाहिए, इसलिए पते बराबर होना चाहिए।

दोनों के बीच अंतर स्पष्ट हो जाता है कि क्या आप परिणामों पर कुछ गणित:

arr+1arr + sizeof(int) के बराबर हो जाएगा।

((&arr) + 1)arr + sizeof(arr) == arr + sizeof(int) * 3

संपादित के बराबर हो जाएगा: मानक इसलिए कहते हैं क्योंकि: कैसे/ऐसा क्यों होता है, इस सवाल का जवाब काफी सरल है के रूप में।

जब यह sizeof ऑपरेटर या एकल & ऑपरेटर के संकार्य है, या एक स्ट्रिंग शाब्दिक एक सरणी प्रारंभ करने में प्रयोग किया जाता है के अलावा, एक अभिव्यक्ति: विशेष रूप से, यह (§6.3.2.1/3) कहते हैं जिसमें टाइप '' सरणी प्रकार '' को '' पॉइंटर टू टाइप 'प्रकार के साथ एक अभिव्यक्ति में परिवर्तित किया गया है जो सरणी ऑब्जेक्ट के प्रारंभिक तत्व को इंगित करता है और यह एक लाभा नहीं है।

[नोट: यह विशेष उद्धरण सी 99 मानक से है, लेकिन मेरा मानना ​​है कि सी और सी ++ मानकों के सभी संस्करणों में समान भाषा है]।

पहला मामला (arr अपने आप में) में, arr sizeof के संकार्य, के रूप में इस्तेमाल नहीं किया जा रहा है एकल &, आदि, तो यह प्रकार में बदल जाती है (प्रचार नहीं किया) "सूचक टाइप करने के लिए" (इस में मामला, "सूचक करने के लिए सूचक")। ताकि रूपांतरण नहीं जगह ले करता है -

दूसरे मामले (&arr) में, नाम स्पष्ट रूप से है एकल & ऑपरेटर के संकार्य के रूप में इस्तेमाल किया जा रहा।

+0

@MooingDuck: आप कहां (सोचते हैं) एक सूचक के पते से संबंधित कुछ भी देखते हैं? (संकेत: यहां ऐसी कोई चीज़ नहीं है)। यहां कोई प्रचार शामिल नहीं है। –

+0

आप बताते हैं कि 'arr' 'int' को 'int' के लिए एक सूचक बनाता है, जो संदिग्ध है, और संभवतः भ्रामक है। –

+0

मुझे यकीन नहीं है कि मैं आपका उद्धरण समझता हूं।हम यूनरी और ऑपरेटर पर चर्चा कर रहे हैं और आपका उद्धरण कहता है कि "इसे छोड़कर [...] यूनरी और ऑपरेटर ..."। – ragnarius

2

पॉइंटर्स और सरणी का अक्सर समान व्यवहार किया जा सकता है, लेकिन अंतर हैं। एक पॉइंटर में मेमोरी लोकेशन होता है, इसलिए आप पॉइंटर का पता ले सकते हैं। लेकिन एक सरणी में रनटाइम पर कुछ भी इंगित नहीं करता है। तो एक सरणी का पता लेना संकलक के लिए है, जो कि पहले तत्व के पते के समान ही परिभाषित किया गया है। जो समझ में आता है, उस वाक्य को जोर से पढ़ना।

4

वे समान नहीं हैं।

arr एक प्रकार int [3] की lvalue है:

एक और अधिक सख्त स्पष्टीकरण सा। arr का उपयोग करने के लिए cout << arr जैसे कुछ अभिव्यक्तियों में परिणामस्वरूप लैवल्यू-टू-रावल्यू रूपांतरण होगा, क्योंकि सरणी प्रकार के कोई भाग नहीं हैं, इसे int * के प्रकार के रूप में परिवर्तित किया जाएगा और &arr[0] के बराबर मान के साथ परिवर्तित किया जाएगा। यह वही है जो आप प्रदर्शित कर सकते हैं।

&arr प्रकार int (*)[3] के rvalue, सरणी वस्तु ही की ओर इशारा करते है। यहां कोई जादू नहीं :-) यह सूचक &arr[0] के समान पते पर इंगित करता है क्योंकि सरणी ऑब्जेक्ट और उसका पहला सदस्य स्मृति में सटीक उसी स्थान पर प्रारंभ होता है। यही कारण है कि उन्हें प्रिंट करते समय आपका एक ही परिणाम होता है।


पुष्टि करते हैं कि वे अलग हैं एक आसान तरीका है *(arr) और *(&arr) तुलना कर रहा है: पहले प्रकार int के lvalue है और दूसरे प्रकार int[3] के lvalue है।

संबंधित मुद्दे