c - शकर - हिस्ट्री ऑफ़ प्रोग्रामिंग लैंग्वेजेज




सरणी के साथ, यह मामला क्यों है[5]== 5[ए]? (12)

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

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

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

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

एक में, प्रतीक एक पते पर है जो सरणी की शुरुआत है, और प्रतीक पी एक पते पर है जहां एक सूचक संग्रहित होता है, और उस स्मृति स्थान पर पॉइंटर का मान सरणी की शुरुआत है।

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

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


ऐसा लगता है कि दीना की समस्या के बारे में कोई बात नहीं है:

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


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

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

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

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

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

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

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


टेड जेन्सेन द्वारा सी में पॉइंटर्स और ARRAYS पर एक ट्यूटोरियल में इसकी बहुत अच्छी व्याख्या है।

टेड जेन्सेन ने इसे समझाया:

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

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

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

char a[20];

लिख रहे हैं

a[3] = 'x';

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

3[a] = 'x';

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

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)

}

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


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

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

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

लेकिन इस मामले में अतिरिक्तता की कमजोरी नहीं है।

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

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

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

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

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

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

इस मामले में i + p और i[p] दोनों अवैध होंगे।

सी ++ शब्दों में, हमारे पास वास्तव में अधिभारित + ऑपरेटरों के दो सेट होते हैं, जिन्हें संक्षेप में वर्णित किया जा सकता है:

pointer operator+(pointer p, integer i);

तथा

pointer operator+(integer i, pointer p);

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

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

सी ++ ने सी से इस परिभाषा को विरासत में मिला, जिसने इसे बी से प्राप्त किया (सरणी इंडेक्सिंग की कम्यूटिटीविटी का स्पष्ट रूप से 1 9 72 के उपयोगकर्ताओं के संदर्भ में बी का उल्लेख किया गया है), जिसे इसे BCPL (मैनुअल दिनांक 1 9 67) से मिला, जो इसे भी यहां से प्राप्त कर सकता है पहले की भाषाएं (सीपीएल? अल्गोल?)।

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

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

और सालों से, उस नियम में किए गए किसी भी बदलाव से मौजूदा कोड तोड़ दिया होगा (हालांकि 1 9 8 9 एएनएसआई सी मानक एक अच्छा मौका हो सकता है)।

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

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


सचमुच प्रश्न का उत्तर देने के लिए। यह हमेशा सत्य नहीं है कि 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

सी में

 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

सूचक एक "परिवर्तनीय" है

सरणी नाम एक "निमोनिक" या "समानार्थी" है

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

a[2] बराबर है [ए] क्योंकि यह दोनों पर आंतरिक संचालन है

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

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


सी में पॉइंटर्स के लिए, हमारे पास है

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

और भी

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

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


सी-भाषा सूचक और सरणी में एक दूसरे के बहुत करीब हैं, एक सरणी को pointer के रूप में विभाजित किया जा सकता है। सरणी का नाम अपने पहले तत्व के लिए एक सूचक है। तो अगर एसीडाटा चरित्र की एक सरणी है तो "एसीडाटा" अपने पहले तत्व का पता होगा। आप यह भी कह सकते हैं कि "एसीडाटा" एसीडाटा [0] के समान है।

सी मानक के अनुसार, हम एक सूचक के रूप में एक 1 डी सरणी का प्रतिनिधित्व कर सकते हैं।

नीचे अभिव्यक्ति देखें,

एसीडाटा [i] = * (एसीडाटा + i); सूचकांक के रूप में ---------> 1 डी सरणी

तो अगर मैं = 5;

सीडीटा [5] = * (एसीडाटा +5);

हम नीचे के रूप में अभिव्यक्ति का प्रतिनिधित्व भी कर सकते हैं,

सीडीटा [5] = * (5 + एसीडाटा);

तो अब, हम लिख सकते हैं

सीडीटा [5] = 5 [सीडीटा];

नीचे कोड देखें,

#include <stdio.h>

int main(int argc, char *argv[]) {

 char cData  [] = {'w', 'o', 'r', 'l' ,'d' }; // character array

 int index = 0;

 for(index = 0; index < sizeof(cData ); ++index)
 {
     printf("Array element access by pointer = %c\n\n",cData[index]);

     printf("Array element access by   array = %c\n\n",index[cData]);
 }


    return 0;
}

संदर्भ, https://aticleworld.com/array-in-c/


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





pointer-arithmetic