X [0]! = X [0] [0]! = X [0] [0] [0] क्यों है?


149

मैं C ++ का थोड़ा अध्ययन कर रहा हूं और मैं संकेत दे रहा हूं। मैं समझता हूं कि मैं घोषणा करके 3 स्तर का संकेत दे सकता हूं:

int *(*x)[5];

इसलिए यह *x5 तत्वों की एक पॉइंटर को इंगित करता है जो इंगित करता है int। यह भी मैं जानता हूं x[0] = *(x+0);, x[1] = *(x+1)और इसी तरह ...।

तो, उपरोक्त घोषणा को देखते हुए, क्यों है x[0] != x[0][0] != x[0][0][0]?


58
x[0], x[0][0]और x[0][0][0]विभिन्न प्रकार हैं। उनकी तुलना नहीं की जा सकती। आपका क्या मतलब है !=?
बोलाव

4
@celticminstrel वे समान नहीं हैं: int **x[5]5 तत्वों की एक सरणी है। एक तत्व सूचक के लिए सूचक है int`
bolov

5
@celticminstrel int** x[5]पाँच पॉइंटर्स की एक सरणी होगी जो पॉइंटर्स को इंगित करती है जो इंट को इंगित करती है। int *(*x)[5]पाँच पॉइंटर्स के एक पॉइंट के लिए एक पॉइंटर है जो इंट को इंगित करता है।
इमली

5
@celticminstrel दाएं-बाएं नियम , सर्पिल नियम , सी जिबरिश and अंग्रेजी और आपका ' तीन सितारा प्रोग्रामर बनने की राह पर :)
bolov

5
@ Leo91: सबसे पहले, आपके पास दो स्तरों के संकेत हैं यहां तीन नहीं। दूसरी बात, क्या x[0] != x[0][0] != x[0][0][0]मतलब है? यह C ++ में मान्य तुलना नहीं है। यहां तक ​​कि अगर आप इसे में विभाजित करते हैं x[0] != x[0][0]और x[0][0] != x[0][0][0]यह अभी भी मान्य नहीं है। तो, आपके प्रश्न का क्या अर्थ है?
एनटी

जवाबों:


261

x5 पॉइंटर्स से लेकर सरणी तक का पॉइंटर है int। 5 पॉइंटर्स की
x[0]एक सरणी है int
x[0][0]एक के लिए एक सूचक है int
x[0][0][0]एक है int

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

आप वह देख सकते हैं

  • x[0]एक सरणी है और एक अभिव्यक्ति (कुछ अपवादों के साथ) में उपयोग किए जाने पर सूचक को इसके पहले तत्व में परिवर्तित कर दिया जाएगा। इसलिए x[0]इसके पहले तत्व का पता देंगे x[0][0]जो है 0x500
  • x[0][0]जिसमें एक का पता intहै 0x100
  • x[0][0][0]का intमान सम्‍मिलित है 10

तो, x[0]के बराबर है &x[0][0]और इसलिए &x[0][0] != x[0][0],।
इसलिए, x[0] != x[0][0] != x[0][0][0]


यह आरेख मेरे लिए थोड़ा भ्रामक है: 0x100बॉक्स के बाईं ओर तुरंत दिखाई देना चाहिए 10, उसी तरह जो 0x500इसके बॉक्स के बाईं ओर दिखाई देता है। इसके बजाय यह बाईं ओर है, और नीचे है।
MM

@MattMcNabb; मुझे नहीं लगता कि यह भ्रामक होना चाहिए, लेकिन अधिक स्पष्टता के लिए आपके सुझाव के अनुसार बदलता है।
सुबह

4
@ झटके - मेरी खुशी :) उस आरेख के महान होने का कारण यह है कि आपको उस स्पष्टीकरण की आवश्यकता भी नहीं है जो आपने दिया था। यह आरेख स्वयं व्याख्यात्मक है कि यह पहले से ही प्रश्न का उत्तर देता है। इस पाठ का अनुसरण केवल एक बोनस है।
रईयरेंग

1
आप एक आरेख सॉफ़्टवेयर का उपयोग भी कर सकते हैं। यह मेरे विचारों को व्यवस्थित करने के लिए बहुत मदद करता है
rpax

@GrijeshChauhan मैं ofthe कोड की टिप्पणियों के लिए asciiflow का उपयोग करता हूं, प्रस्तुतियों के लिए :) :)
rpax

133
x[0] != x[0][0] != x[0][0][0]

आपके अपने पद के अनुसार है,

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

जो सरलीकृत है

*x != **x != ***x

यह बराबर क्यों होना चाहिए?
पहले एक कुछ सूचक का पता है।
दूसरा एक और सूचक का पता है।
और तीसरा एक कुछ intमूल्य है।


मैं नहीं समझ सकता ... अगर x [0], x [0] [0], x [0] [0] [0] * (x + 0), * (x + 0 + 0) के बराबर है। , * (x + 0 + 0 + 0), उनके अलग-अलग पते क्यों होने चाहिए?
सिंह 91

41
@ Leo91 x[0][0]है (x[0])[0], यानी *((*(x+0))+0), नहीं *(x+0+0)। दूसरे से पहले ही डिरेक्शन होता है [0]
इमली

4
@ सिंह91 x[0][0] != *(x+0+0)जैसा x[2][3] != x[3][2]
özg

@ Leo91 दूसरी टिप्पणी जो आपको "अभी मिल गई है" को हटा दिया गया था। क्या आपको कुछ समझ नहीं आ रहा है (जो उत्तर में बेहतर बताया जा सकता है), या यह आपका काम नहीं है? (कुछ लोग बहुत अधिक जानकारीपूर्ण सामग्री के बिना टिप्पणियों को हटाना पसंद करते हैं)
deviantfan

@deviantfan क्षमा करें, मैं समझ नहीं सकता कि आपका क्या मतलब है। मैं जवाबों के साथ-साथ कई टिप्पणियों को भी समझता हूं, जिनसे मदद मिली कि अवधारणा स्पष्ट करती है।
सिंह 91

50

यहाँ आपके पॉइंटर का मेमोरी लेआउट है:

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0]पैदावार "सरणी का पता",
x[0][0]"सूचक 0",
x[0][0][0]पैदावार "कुछ पूर्णांक" देता है।

मेरा मानना ​​है, अब यह स्पष्ट होना चाहिए कि वे सभी अलग-अलग क्यों हैं।


उपरोक्त बुनियादी समझ के लिए पर्याप्त है, यही वजह है कि मैंने इसे जिस तरह से लिखा था, उसे लिखा। हालांकि, जैसा कि हक सही बताता है, पहली पंक्ति 100% सटीक नहीं है। तो यहाँ सभी बारीक विवरण आते हैं:

सी भाषा की परिभाषा से, x[0]पूर्णांक के पूर्णांक का मान है। हालाँकि, सरणियाँ कुछ ऐसी हैं जो आप वास्तव में सी के साथ कुछ भी नहीं कर सकते हैं। आप हमेशा या तो उनके पते या उनके तत्वों में हेरफेर करते हैं, कभी भी संपूर्ण सरणी पूरी नहीं होती है:

  1. आप ऑपरेटर x[0]को पास कर सकते हैं sizeof। लेकिन यह वास्तव में मूल्य का उपयोग नहीं है, इसका परिणाम केवल प्रकार पर निर्भर करता है।

  2. आप इसका पता ले सकते हैं, जो xकि प्रकार के साथ "सरणी का पता" का मान देता है int*(*)[5]। दूसरे शब्दों में:&x[0] <=> &*(x + 0) <=> (x + 0) <=> x

  3. में अन्य सभी संदर्भों , का मान x[0]सरणी में पहला तत्व के लिए सूचक में क्षय होगा। यही है, एक सूचक "सरणी का पता" और प्रकार के साथ int**। इसका प्रभाव वैसा ही है, जैसे आपने xकिसी प्रकार के पॉइंटर को डाला हो int**

3. मामले में सरणी-सूचक क्षय के कारण, x[0]आखिरकार एक सूचक में परिणाम के सभी उपयोग जो सूचक सरणी की शुरुआत को इंगित करते हैं; कॉल printf("%p", x[0])"सरणी का पता" के रूप में लेबल की गई मेमोरी कोशिकाओं की सामग्री को प्रिंट करेगा।


1
x[0]सरणी का पता नहीं है।
हॉक

1
@ हैक्स हाँ, मानक के अक्षर के बाद, x[0]सरणी का पता नहीं है, यह सरणी ही है। मैंने इस बारे में गहराई से स्पष्टीकरण जोड़ा है, और मैंने क्यों लिखा है कि x[0]"सरणी का पता" है। मुझे उम्मीद है आप इसे पसंद करेंगे।
cmaster - मोनिका

भयानक रेखांकन जो इसे पूरी तरह से अच्छी तरह से समझाते हैं!
एमके

"हालांकि, सरणियां कुछ ऐसी हैं जो आप वास्तव में सी के साथ कुछ भी नहीं कर सकते हैं।" -> काउंटर उदाहरण: printf("%zu\n", sizeof x[0]);सरणी के आकार की रिपोर्ट करता है, न कि सूचक का आकार।
chux -

@ chux-ReinstateMonica और मैंने कहा कि "आप हमेशा उनके पते या उनके तत्वों में हेरफेर करते हैं, कभी भी पूरे सरणी को एक पूरे के रूप में नहीं", इसके बाद गणना के बिंदु 1 पर जहां मैं प्रभाव के बारे में बात करता हूं sizeof x[0]...
cmaster मोनिका

18
  • x[0]सबसे बाहरी पॉइंटर ( पॉइंटर के आकार 5 से पॉइंटर के इंट के लिए पॉइंटर) और परिणाम में पॉइंटर से साइज 5 की एक सरणी होती है int;
  • x[0][0]dereferences सबसे बाहरी सूचक और सरणी को अनुक्रमित करता है, जिसके परिणामस्वरूप एक सूचक होता है int;
  • x[0][0][0] सब कुछ dereferences, जिसके परिणामस्वरूप एक ठोस मूल्य है।

वैसे, यदि आप कभी भी इस तरह की घोषणाओं से भ्रमित महसूस करते हैं, तो cdecl का उपयोग करें ।


11

कदम से कदम भाव पर विचार करते हैं x[0], x[0][0]और x[0][0][0]

जैसा xकि निम्नलिखित तरीके से परिभाषित किया गया है

int *(*x)[5];

तब अभिव्यक्ति x[0]प्रकार की एक सरणी है int *[5]। ध्यान रखें कि अभिव्यक्ति अभिव्यक्ति x[0]के बराबर है *x। यह एक व्यूह को इंगित करते हुए एक सरणी है जो हमें सरणी को ही मिलती है। इसे y की तरह निरूपित करें जो कि हमारे पास एक घोषणा है

int * y[5];

अभिव्यक्ति x[0][0]के बराबर है y[0]और इसके प्रकार हैं int *। इसे z की तरह निरूपित करते हैं जो कि हमारे पास एक घोषणा है

int *z;

अभिव्यक्ति अभिव्यक्ति x[0][0][0]के बराबर है y[0][0]जो बदले में अभिव्यक्ति के बराबर है z[0]और इसके प्रकार हैं int

तो हमारे पास

x[0] प्रकार है int *[5]

x[0][0] प्रकार है int *

x[0][0][0] प्रकार है int

इसलिए वे विभिन्न प्रकारों की वस्तुएं हैं और विभिन्न आकारों के माध्यम से।

उदाहरण के लिए भागो

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;

10

पहली बात मुझे यह कहना पड़ेगा

x [0] = * (x + 0) = * x;

x [0] [0] = * (* (x + 0) + 0) = * * x;

x [०] [०] [०] = * (* (* (x + 0) + ०)) = * * * x;

तो * x * * * x ≠ * * * x

निम्नलिखित तस्वीर से सभी चीजें स्पष्ट हैं।

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

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

यह केवल एक उदाहरण है, जहाँ x [0] [0] [0] = 10 का मान है

और x [0] [0] [0] का पता 1001 है

वह पता x [0] [0] = 1001 में संग्रहीत है

और का पता एक्स [0] [0] है 2000

और वह पता x [0] = 2000 पर संग्रहीत है

तो एक्स [0] [0] [0] एक्स [0] [0] एक्स [0]

editings

कार्यक्रम 1:

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

उत्पादन

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

कार्यक्रम 2:

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

उत्पादन

10   -1074058436   -1074058436   -1074058436 

3
आपका जवाब भ्रामक है। x[0]चींटी का पता नहीं है। इसकी एक सरणी है। यह अपने पहले तत्व को इंगित करने के लिए क्षय होगा।
बजे

उम्म्म्म… इसका क्या मतलब है? आपका संपादन आपके गलत उत्तर के लिए केक पर चेरी जैसा है। यह कोई मतलब नहीं है
haccks

@ झटके यदि यह अकेले पॉइंटर्स का उपयोग कर रहा है, तो यह उत्तर सही होगा। Array
apm

7

यदि आप सरणियों को वास्तविक दुनिया के दृष्टिकोण से देखते हैं, तो यह इस प्रकार दिखाई देगा:

x[0]बक्से से भरा एक माल कंटेनर है।
x[0][0]फ्रेट कंटेनर के भीतर एक एकल टोकरा, शोबॉक्स से भरा हुआ है।
x[0][0][0]फ्रेट कंटेनर के अंदर टोकरा के अंदर एक एकल थरथराना है।

भले ही यह फ्रेट कंटेनर में एकमात्र टोकरा में एकमात्र शोबॉक्स था, लेकिन यह अभी भी एक शोबॉक्स है और न ही एक फ्रेट कंटेनर है


1
x[0][0]कागज के टुकड़ों से भरा एक भी टोकरा नहीं होगा जो उन पर लिखे गए शोबॉक्स का स्थान है?
वचर्जिन

4

C ++ में एक सिद्धांत है ताकि: एक चर की घोषणा चर का उपयोग करने के तरीके को इंगित करे। अपनी घोषणा पर विचार करें:

int *(*x)[5];

इसे फिर से लिखा जा सकता है (स्पष्ट के लिए):

int *((*x)[5]);

सिद्धांत के कारण, हमारे पास:

*((*x)[i]) is treated as an int value (i = 0..4)
 (*x)[i] is treated as an int* pointer (i = 0..4)
 *x is treated as an int** pointer
 x is treated as an int*** pointer

इसलिए:

x[0] is an int** pointer
 x[0][0] = (x[0]) [0] is an int* pointer
 x[0][0][0] = (x[0][0]) [0] is an int value

तो आप अंतर का पता लगा सकते हैं।


1
x[0]5 इंच की एक सरणी है, एक सूचक नहीं है। (यह अधिकांश संदर्भों में एक सूचक को क्षय कर सकता है लेकिन यहाँ अंतर महत्वपूर्ण है)।
MM

ठीक है, लेकिन आपको कहना चाहिए: x [0] 5 पॉइंट int * की एक सरणी है
Nghia Bui

@MattMcNabb प्रति सही व्युत्पत्ति देने के लिए: a *(*x)[5]है int, इसलिए a (*x)[5]है int *, इसलिए a *xहै (int *)[5], इसलिए a xहै *((int *)[5])। यही है, xसूचक के 5-सरणी के लिए एक सूचक है int
वचर्जिन

2

आप मूल्य द्वारा विभिन्न प्रकारों की तुलना करने की कोशिश कर रहे हैं

यदि आप पते ले लेते हैं तो आपको वह प्राप्त हो सकता है जो आप अपेक्षा करते हैं

ध्यान रखें कि आपकी घोषणा से फर्क पड़ता है

 int y [5][5][5];

तुलना आप चाहते हैं की अनुमति होगी, क्योंकि y, y[0], y[0][0], y[0][0][0]विभिन्न मूल्यों और प्रकार, लेकिन एक ही पते के लिए होता है

int **x[5];

सन्निहित स्थान पर कब्जा नहीं करता है।

xऔर x [0]एक ही पते है, लेकिन x[0][0]और x[0][0][0]अलग-अलग पतों पर प्रत्येक रहे हैं


2
int *(*x)[5]से भिन्न हैint **x[5]
MM

2

pएक पॉइंटर होने के नाते : आप डीरेफरेंस के साथ स्टैकिंग कर रहे हैं p[0][0], जो इसके बराबर है *((*(p+0))+0)

C संदर्भ (&) और डीरेफेरेंस (*) संकेतन में:

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

के बराबर है:

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

यह देखें कि, & * को हटाया जा सकता है, बस इसे हटा दें:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)

आप अपने पहले वाक्य के बाद सब कुछ के साथ क्या दिखाने की कोशिश कर रहे हैं? आपके पास बहुत भिन्नताएं हैं p == p&(&p[0])[0]से भिन्न हैp[0][0]
MM

उस व्यक्ति ने पूछा कि 'x [0]! = X [0] [0]! = X [0] [0] [0]' जब x एक पॉइंटर है, है ना? मैंने उसे दिखाने की कोशिश की, कि जब वह [0] के ढेर हो जाए, तो उसे dereference (*) के C नोटेशन द्वारा फँसाया जा सकता है। तो, यह उसे x के बराबर x [0] होने का सही अंकन दिखाने की कोशिश है, x [0] को फिर से & के साथ संदर्भित करते हुए, और इसी तरह।
लुसियानो

1

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

इसका कारण अन्य उत्तरों से नहीं समझा जा सकता है कि सभी चित्रण, जबकि सहायक और निश्चित रूप से अधिकांश परिस्थितियों में उचित हैं, उस स्थिति को कवर करने में विफल होते हैं जहां सूचक xखुद को इंगित करता है।

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

नोट: इस कार्यक्रम में व्यवहार अपरिभाषित है, लेकिन मैं इसे विशुद्ध रूप से किसी ऐसी चीज़ के एक दिलचस्प प्रदर्शन के रूप में पोस्ट कर रहा हूं जो पॉइंटर्स कर सकते हैं, लेकिन ऐसा नहीं करना चाहिए

#include <stdio.h>

int main () {
  int *(*x)[5];

  x = (int *(*)[5]) &x;

  printf("%p\n", x[0]);
  printf("%p\n", x[0][0]);
  printf("%p\n", x[0][0][0]);
}

यह C89 और C99 दोनों में चेतावनी के बिना संकलित करता है, और आउटपुट निम्न है:

$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c

दिलचस्प रूप से पर्याप्त है, तीनों मूल्य समान हैं। लेकिन यह एक आश्चर्य नहीं होना चाहिए! सबसे पहले, चलो कार्यक्रम को तोड़ते हैं।

हम x5 तत्वों की एक सरणी के लिए एक पॉइंटर के रूप में घोषित करते हैं, जहां प्रत्येक तत्व इंट के लिए टाइप पॉइंटर का है। यह घोषणा रनटाइम स्टैक पर 4 बाइट्स आवंटित करती है (या आपके कार्यान्वयन के आधार पर और अधिक; मेरे मशीन पॉइंटर्स 4 बाइट्स पर हैं), इसलिए xएक वास्तविक मेमोरी लोकेशन का जिक्र है। भाषाओं के सी परिवार में, सामग्री xकेवल कचरा है, स्थान के पिछले उपयोग से कुछ बचा है, इसलिए xस्वयं कहीं भी इंगित नहीं करता है - निश्चित रूप से आवंटित स्थान पर नहीं।

इसलिए, स्वाभाविक रूप से, हम चर का पता ले सकते हैं xऔर इसे कहीं रख सकते हैं, इसलिए ठीक यही हम करते हैं। लेकिन हम आगे बढ़ेंगे और इसे x में डाल देंगे। चूंकि &xएक अलग प्रकार है x, इसलिए हमें एक कास्ट करने की आवश्यकता है ताकि हमें चेतावनी न मिले।

मेमोरी मॉडल कुछ इस तरह दिखाई देगा:

0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+

तो पते पर स्मृति के 4-बाइट ब्लॉक में 0xbfd9198cहेक्साडेसिमल मान के अनुरूप बिट पैटर्न होता है 0xbfd9198c। काफी सरल।

इसके बाद, हम तीन मानों का प्रिंट आउट लेते हैं। अन्य उत्तर बताते हैं कि प्रत्येक अभिव्यक्ति का क्या अर्थ है, इसलिए अब संबंध स्पष्ट होना चाहिए।

हम देख सकते हैं कि मूल्य समान हैं, लेकिन केवल बहुत ही निम्न स्तर के अर्थों में ... उनके बिट पैटर्न समान हैं, लेकिन प्रत्येक अभिव्यक्ति के साथ जुड़े प्रकार के डेटा का अर्थ है कि उनके व्याख्या किए गए मान अलग-अलग हैं। उदाहरण के लिए, यदि हम x[0][0][0]प्रारूप स्ट्रिंग का उपयोग करके प्रिंट करते हैं, तो हमें %dएक बड़ी नकारात्मक संख्या मिलेगी, इसलिए "मान" व्यवहार में, भिन्न हैं, लेकिन बिट पैटर्न समान है।

यह वास्तव में बहुत सरल है ... आरेखों में, तीर अलग-अलग लोगों के बजाय एक ही स्मृति पते पर इंगित करते हैं। हालाँकि, जब हम अनिर्धारित व्यवहार से अपेक्षित परिणाम के लिए बाध्य करने में सक्षम थे, तो यह सिर्फ - अपरिभाषित है। यह उत्पादन कोड नहीं है, बल्कि पूर्णता के लिए केवल एक प्रदर्शन है।

एक उचित स्थिति में, आप malloc5 अंतर बिंदुओं की सरणी बनाने के लिए उपयोग करेंगे , और फिर से उस सरणी में इंगित किए गए इन्ट्स बनाने के लिए। mallocहमेशा एक अद्वितीय पता देता है (जब तक कि आप मेमोरी से बाहर नहीं होते हैं, उस स्थिति में यह NULL या 0 लौटाता है), इसलिए आपको कभी भी इस तरह के सेल्फ-रेफरेंशियल पॉइंटर्स के बारे में चिंता करने की आवश्यकता नहीं होगी।

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


मैं कहूंगा कि बिंदुओं का एक और अजीब उपयोग मैंने कभी देखा है।
जूल

@haccks हाँ, यह बहुत अजीब है, लेकिन जब आप इसे तोड़ते हैं, तो यह अन्य उदाहरणों की तरह ही बुनियादी है। यह सिर्फ एक ऐसा मामला होता है जहां बिट पैटर्न सभी समान होते हैं।
पुरग

आपका कोड अपरिभाषित व्यवहार का कारण बनता है। x[0]वास्तव में सही प्रकार के एक वैध वस्तु का प्रतिनिधित्व नहीं करता है
MM

@MattMcNabb यह अपरिभाषित है, और मैं वास्तव में इसके बारे में बहुत स्पष्ट हूं। मैं प्रकार के संबंध में असहमत हूं। xएक सरणी के लिए एक संकेतक है, इसलिए हम []उस सूचक से ऑफसेट को निर्दिष्ट करने के लिए ऑपरेटर का उपयोग कर सकते हैं और इसे dereferencing कर सकते हैं। वहाँ क्या अजीब है? परिणाम x[0]एक सरणी है, और सी शिकायत नहीं करता है यदि आप प्रिंट करते हैं तो इसका उपयोग करना %pहै कि यह वैसे भी कैसे लागू किया गया है।
पुरग

और -pedanticध्वज के साथ इसे संकलित करने से कोई चेतावनी नहीं
मिलती

0

इस प्रकार की है int *(*x)[5]कि int* (*)[5]एक सूचक के संकेत के लिए 5 ints की एक सरणी।

  • x5 पॉइंटर्स इन्टस (प्रकार के साथ एक पता int* (*)[5]) के पहले सरणी का पता है
  • x[0]5 पॉइंटर्स टू इन्ट्स (टाइप के साथ एक ही पता int* [5]) के पहले एरे का पता (ऑफसेट एड्रेस एक्स बाय 0*sizeof(int* [5])इंडेक्स * साइज़-ऑफ-टाइप-बीइंग-टू-डीरेफरेंस)
  • x[0][0]सरणी में एक इंट का पहला पॉइंटर है (टाइप के साथ एक ही पता int*) (ऑफसेट एड्रेस 0*sizeof(int* [5])बी बाय और डीएफेरेंस और फिर बाय 0*sizeof(int*)और डीरेफेरेंस)
  • x[0][0][0]पहले पूर्णांक के लिए एक पूर्णांक सूचक द्वारा की ओर इशारा किया (की भरपाई का पता एक्स की जा रही है 0*sizeof(int* [5])और भिन्नता और द्वारा उस पते ऑफसेट 0*sizeof(int*)और भिन्नता और द्वारा उस पते ऑफसेट 0*sizeof(int)और भिन्नता)

का प्रकार है int *(*y)[5][5][5], int* (*)[5][5][5]यानी कि 5x5x5 पॉइंटर्स की 3 डी सरणी के लिए एक पॉइंटर को एक पॉइंटर

  • x प्रकार के साथ ints में 5x5x5 पॉइंटर्स के पहले 3 डी सरणी का पता है int*(*)[5][5][5]
  • x[0]5x5x5 पॉइंटर्स की पहली 3 डी सारणी का पता किलों पर है (ऑफसेट एड्रेस 0*sizeof(int* [5][5][5])बी बाय और डीरेफेरेंस)
  • x[0][0]5x5 पॉइंटर्स के पहले 2d सरणी के इन्ट्स का पता है (ऑफसेट एड्रेस x बाय 0*sizeof(int* [5][5][5])और डीएफरेंस फिर ऑफसेट एड्रेस 0*sizeof(int* [5][5]))
  • x[0][0][0]5 पॉइंटर्स इन्ट्स के पहले सरणी का पता है (ऑफसेट एड्रेस x बाय 0*sizeof(int* [5][5][5])और डीएफेरेंस और उस एड्रेस को 0*sizeof(int* [5][5])ऑफसेट करके और उस एड्रेस को ऑफसेट करके 0*sizeof(int* [5]))
  • x[0][0][0][0]सरणी में एक इंट का पहला सूचक है (ऑफसेट एड्रेस x by 0*sizeof(int* [5][5][5])और dereference और उस पते को 0*sizeof(int* [5][5])ऑफसेट करके और उस पते को 0*sizeof(int* [5])ऑफसेट करके और उस पते को ऑफसेट करके 0*sizeof(int*)और dereference द्वारा ऑफसेट करें )
  • x[0][0][0][0][0]सूचक द्वारा किसी int (ऑफसेट एड्रेस x by 0*sizeof(int* [5][5][5])और dereference को ऑफसेट करके 0*sizeof(int* [5][5])और उस पते को 0*sizeof(int* [5])ऑफसेट करके और उस पते को ऑफसेट करके और उस पते को 0*sizeof(int*)ऑफसेट करके 0*sizeof(int)और dereference द्वारा ऑफसेट किया गया है और dereference द्वारा उस पते को ऑफ़सेट किया जाता है)

सरणी क्षय के लिए:

void function (int* x[5][5][5]){
  printf("%p",&x[0][0][0][0]); //get the address of the first int pointed to by the 3d array
}

यह पास होने के बराबर है int* x[][5][5]या int* (*x)[5][5]वे सभी बाद के लिए क्षय हैं। यही कारण है कि आपको x[6][0][0]फ़ंक्शन में उपयोग करने के लिए एक संकलक चेतावनी नहीं मिलेगी, लेकिन आप x[0][6][0]उस आकार की जानकारी संरक्षित होने के कारण करेंगे

void function (int* (*x)[5][5][5]){
  printf("%p",&x[0][0][0][0][0]); //get the address of the first int pointed to by the 3d array
}
  • x[0] 5x5x5 पॉइंटर्स की प्रथम 3 डी सरणी का पता किट्स में है
  • x[0][0] 5x5 पॉइंटर्स के प्रथम 2d सरणी का संकेत है
  • x[0][0][0] 5 पॉइंटर्स इन्ट्स के पहले एरे का पता है
  • x[0][0][0][0] सरणी में एक इंट का पहला सूचक है
  • x[0][0][0][0][0] सूचक द्वारा किसी int को इंगित करने वाला पहला int है

अंतिम उदाहरण में, यह उपयोग करने के लिए शब्दार्थ से बहुत स्पष्ट है *(*x)[0][0][0] बजाय है x[0][0][0][0][0], इसका कारण यह है कि पहले और आखिरी [0]को एक सूचक के रूप में एक बहुआयामी सरणी में एक सूचकांक के बजाय एक बहुवचन सरणी के रूप में व्याख्या की जाती है। वे हालांकि समान हैं क्योंकि (*x) == x[0]शब्दार्थ की परवाह किए बिना। आप यह भी इस्तेमाल कर सकते हैं *****x, जो ऐसा लगेगा जैसे आप पॉइंटर को 5 बार डिफाइन कर रहे हैं, लेकिन यह वास्तव में बिल्कुल एक ही समझा जाता है: एक ऑफसेट, एक डीरेफेरेंस, एक डीरेफेरेंस, एक सरणी में 2 ऑफसेट और एक डीरेफेरेंस, विशुद्ध रूप से टाइप के कारण आप ऑपरेशन को लागू कर रहे हैं।

अनिवार्य रूप से जब आप [0] या *एक *गैर सरणी प्रकार के लिए, यह एक ऑफसेट है और पूर्ववर्ती के आदेश के कारण एक dereference है *(a + 0)

जब आप [0] या *एक *सरणी प्रकार के लिए तो यह एक ऑफसेट है तो एक बेकार dereference (एक ही पता प्राप्त करने के लिए कंपाइलर द्वारा dereference का समाधान किया जाता है - यह एक आदर्श ऑपरेशन है)।

जब आप [0] या *1 डी सरणी प्रकार के साथ टाइप करते हैं तो यह एक ऑफसेट होता है फिर एक डीरेफेरेंस होता है

अगर तुम [0] या **एक 2d सरणी प्रकार है तो यह केवल एक ऑफसेट है एक ऑफसेट और फिर एक आदर्श dereference।

अगर तुम [0][0][0] या ***एक 3 डी सरणी प्रकार है तो यह एक ऑफसेट + बेरोजगारी से बचाव है, तो एक ऑफसेट + बेरोजगारी से बचाव तो एक ऑफसेट + बेरोजगारी से बचाव तो एक परित्याग। सच्चा मात्र तभी होता है जब सरणी प्रकार पूरी तरह से छीन लिया जाता है।

के उदाहरण के लिए int* (*x)[1][2][3]प्रकार लिए क्रम में अलिखित है।

  • x एक प्रकार है int* (*)[1][2][3]
  • *x एक प्रकार है int* [1][2][3] (ऑफसेट 0 + idempotent dereference)
  • **x एक प्रकार है int* [2][3] (ऑफसेट 0 + idempotent dereference)
  • ***x एक प्रकार है int* [3] (ऑफसेट 0 + idempotent dereference)
  • ****x एक प्रकार है int* (ऑफसेट 0 + dereference)
  • *****xप्रकार है int(ऑफसेट 0 + dereference)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.