नकारात्मक सरणी सूचकांक क्यों समझ में आते हैं?


14

मुझे C प्रोग्रामिंग में एक अजीब अनुभव हुआ। इस कोड पर विचार करें:

int main(){
  int array1[6] = {0, 1, 2, 3, 4, 5};
  int array2[6] = {6, 7, 8, 9, 10, 11};

  printf("%d\n", array1[-1]);
  return 0;
}

जब मैं इसे संकलित और चलाता हूं, तो मुझे कोई त्रुटि या चेतावनी नहीं मिलती है। जैसा कि मेरे लेक्चरर ने कहा, एरे इंडेक्स -1दूसरे वेरिएबल को एक्सेस करता है। मैं अभी भी उलझन में हूँ, पृथ्वी पर एक प्रोग्रामिंग भाषा में यह क्षमता क्यों है? मेरा मतलब है, नकारात्मक सरणी सूचकांकों की अनुमति क्यों दें?


2
जबकि यह प्रश्न सी के रूप में ठोस प्रोग्रामिंग भाषा से प्रेरित है, मुझे लगता है कि इसे एक वैचारिक प्रश्न के रूप में समझा जा सकता है जो यहां (यदि मुश्किल से) है।
राफेल

7
@ राफेल मैं असहमत हूं और मानता हूं कि यह एसओ पर होना चाहिए, या तो यह पाठ्यपुस्तक अपरिभाषित व्यवहार है (सरणी के बाहर स्मृति का उल्लेख करना) और उचित संकलक झंडे को इस बारे में चेतावनी देनी चाहिए
शाफ़्ट फ्रीक

मैं @ratchetfreak से सहमत हूं। ऐसा लगता है कि वैध सूचकांक सीमा [0, 5] के बाद से संकलक दोष है। जो कुछ भी बाहर है वह एक संकलन / रनटाइम त्रुटि होना चाहिए। सामान्य तौर पर, वैक्टर विशेष रूप से उन कार्यों के मामले होते हैं जिनका पहला तत्व सूचकांक उपयोगकर्ता पर निर्भर होता है। चूंकि सी अनुबंध यह है कि तत्व इंडेक्स 0 से शुरू होते हैं, इसलिए नकारात्मक तत्वों को एक्सेस करने में त्रुटि होती है।
वैल

2
@ राफेल सी के पास विशिष्ट भाषाओँ के दो विशिष्ट गुण हैं, जो यहाँ ऐरे के साथ हैं। एक यह है कि सी में सबरेज़ हैं और -1एक सबर्रे के तत्व को संदर्भित करना एक बड़ा सरणी में उस सरणी से पहले तत्व को संदर्भित करने के लिए एक पूरी तरह से वैध तरीका है। अन्य यह है कि यदि सूचकांक अमान्य है, तो कार्यक्रम अमान्य है, लेकिन अधिकांश कार्यान्वयन में आपको चुप व्यवहार मिलेगा, न कि एक आउट-ऑफ-रेंज त्रुटि।
गाइल्स का SO- दुष्ट होना बंद करें '

4
@ गिल्स अगर यह सवाल का बिंदु है, तो यह वास्तव में स्टैक ओवरफ्लो पर होना चाहिए ।
राफेल

जवाबों:


27

सरणी अनुक्रमण ऑपरेशन a[i]C की निम्नलिखित विशेषताओं से अपना अर्थ प्राप्त करता है

  1. वाक्यविन्यास a[i]के बराबर है *(a + i)। इस प्रकार यह 5[a]5 वें तत्व पर प्राप्त करने के लिए कहने के लिए वैध है a

  2. पॉइंटर-अंकगणित कहता है कि एक सूचक pऔर एक पूर्णांक i, बाइट द्वारा उन्नत p + i सूचक दिया pगयाi * sizeof(*p)

  3. एक सरणी का नाम aबहुत जल्दी से 0 के तत्व के लिए एक सूचक के लिए तैयार हो जाता हैa

वास्तव में, सरणी-अनुक्रमण सूचक-अनुक्रमण का एक विशेष मामला है। एक सूचक किसी भी स्थान पर एक सरणी, अंदर किसी भी मनमाने ढंग से अभिव्यक्ति इंगित कर सकते हैं के बाद से है कि लगता है जैसे p[-1]है नहीं परीक्षा द्वारा गलत है, और इसलिए compilers नहीं (नहीं कर सकता) त्रुटि के रूप में सभी तरह के भाव पर विचार करें।

आपका उदाहरण a[-1]जहां aवास्तव में एक सरणी का नाम है वास्तव में अमान्य है। IIRC, यह अपरिभाषित है यदि अभिव्यक्ति के परिणाम के रूप में एक सार्थक सूचक मान है a - 1जहां aकिसी सरणी के 0 वें तत्व के लिए एक संकेतक जाना जाता है। इसलिए, एक चतुर कंपाइलर इसका पता लगा सकता है और इसे त्रुटि के रूप में चिह्नित कर सकता है। अन्य कंपाइलर अभी भी आज्ञाकारी हो सकते हैं, जबकि आप एक यादृच्छिक स्टैक स्लॉट के लिए आपको एक संकेतक देकर पैर में खुद को शूट करने की अनुमति देते हैं।

कंप्यूटर विज्ञान का उत्तर है:

  • सी में, []ऑपरेटर पॉइंटर्स पर परिभाषित किया गया है, न कि सरणियाँ। विशेष रूप से, यह पॉइंटर अंकगणित और पॉइंटर डेरेफेरेंस के संदर्भ में परिभाषित किया गया है।

  • सी में, एक पॉइंटर अमूर्त रूप (start, length, offset)से इस स्थिति के साथ एक ट्यूपल है 0 <= offset <= length। पॉइंटर अंकगणित को अनिवार्य रूप से ऑफसेट पर अंकगणित उठा दिया जाता है, इस चेतावनी के साथ कि यदि ऑपरेशन का परिणाम सूचक स्थिति का उल्लंघन करता है, तो यह एक अपरिभाषित मूल्य है। एक पॉइंटर को डी-रेफर करने से एक अतिरिक्त अड़चन आती है offset < length

  • C की एक धारणा है, undefined behaviourजो एक संकलक को एक ही संख्या के रूप में उस ट्यूपल का प्रतिनिधित्व करने की अनुमति देता है, और सूचक स्थिति के किसी भी उल्लंघन का पता लगाने की आवश्यकता नहीं है। अमूर्त शब्दार्थ को संतुष्ट करने वाला कोई भी कार्यक्रम ठोस (हानिपूर्ण) शब्दार्थ के साथ सुरक्षित होगा। कुछ भी जो अमूर्त शब्दार्थ का उल्लंघन करता है, संकलक द्वारा स्वीकार किए बिना टिप्पणी के बिना हो सकता है, और यह कुछ भी कर सकता है जो इसके साथ करना चाहता है।


कृपया किसी विशेष प्रोग्रामिंग लैंग्वेज की आइडियोसिंक्रेसिस के आधार पर, सामान्य उत्तर देने का प्रयास करें।
राफेल

6
@ राफेल, प्रश्न स्पष्ट रूप से सी के बारे में था। मुझे लगता है कि मैंने विशिष्ट प्रश्न को संबोधित किया कि सी। कंपाइलर को सी की परिभाषा के भीतर एक प्रतीत होता है कि व्यर्थ अभिव्यक्ति को संकलित करने की अनुमति क्यों है
हरि

विशेष रूप से C के बारे में प्रश्न यहाँ ऑफटॉपिक हैं; सवाल पर मेरी टिप्पणी ध्यान दें।
राफेल

5
मेरा मानना ​​है कि प्रश्न का तुलनात्मक भाषाविज्ञान पहलू अभी भी उपयोगी है। मेरा मानना ​​है कि मैंने एक "कंप्यूटर-विज्ञान" का एक शानदार वर्णन दिया कि क्यों एक विशिष्ट कार्यान्वयन ने एक विशिष्ट ठोस शब्दार्थ का प्रदर्शन किया।
हरि

15

Arrays बस स्मृति के सन्निहित हिस्सा के रूप में बाहर रखी हैं। एक ऐरे एक्सेस जैसे कि [i] को मेमोरी लोकेशन एड्रेसऑफ (ए) + आई में बदल दिया जाता है। यह कोड a[-1]पूरी तरह से समझा जा सकता है, यह केवल सरणी की शुरुआत से पहले पता एक को संदर्भित करता है।

यह पागल लग सकता है, लेकिन इसकी अनुमति देने के कई कारण हैं:

  • यह जाँचना महंगा है कि क्या सूचकांक I [-] सरणी के सीमा के भीतर है।
  • कुछ प्रोग्रामिंग तकनीक वास्तव में इस तथ्य का फायदा उठाती हैं कि a[-1]यह मान्य है। उदाहरण के लिए, अगर मुझे पता है कि aवास्तव में सरणी की शुरुआत नहीं है, लेकिन सरणी के बीच में एक सूचक है, तो a[-1]बस सरणी का तत्व मिलता है जो सूचक के बाईं ओर है।

6
दूसरे शब्दों में, इसका उपयोग शायद नहीं किया जाना चाहिए। अवधि। क्या, आपका नाम डोनाल्ड नुथ है और आप 17 अन्य निर्देशों को बचाने की कोशिश करते हैं? हर तरह से, आगे बढ़ो।
राफेल

उत्तर के लिए धन्यवाद, लेकिन मुझे यह विचार नहीं मिला। BTW मैं इसे बार-बार
पढ़ूंगा

2
@ राफेल: कोला ऑब्जेक्ट मॉडल के कार्यान्वयन के लिए -1 स्थिति का उपयोग करता है vtable: piumarta.com/software/cola/objmodel2.pdf । इस प्रकार खेतों को वस्तु के सकारात्मक भाग में और नकारात्मक अवस्था में संग्रहित किया जाता है। मुझे विवरण याद नहीं है, लेकिन मुझे लगता है कि यह निरंतरता के साथ करना है।
डेव क्लार्क

@ DeZéroToxin: एक सरणी वास्तव में स्मृति में केवल एक स्थान है, इसके बगल में कुछ स्थान हैं जो तार्किक रूप से सरणी का हिस्सा हैं। लेकिन वास्तव में, एक सरणी सिर्फ एक संकेतक है।
डेव क्लार्क

1
@ राफेल, a[-1]के कुछ मामलों के लिए एकदम सही समझ में आता है a, इस विशेष मामले में यह सादा अवैध है (लेकिन संकलक द्वारा पकड़ा नहीं गया)
वॉनब्रांड

4

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


1
मुझे यह उत्तर पसंद है। यह ठीक क्यों है इसका एक वास्तविक कारण देता है।
darxsys

3

एक ऐसी सुविधा का उपयोग मेमोरी आवंटन विधियों को लिखने के लिए कर सकता है जो मेमोरी को सीधे एक्सेस करते हैं। ऐसा एक उपयोग पिछले मेमोरी ब्लॉक की जांच करने के लिए एक नकारात्मक सरणी इंडेक्स का उपयोग करके यह निर्धारित करने के लिए है कि क्या दो ब्लॉक विलय किए जा सकते हैं। मैंने इस सुविधा का उपयोग तब किया है जब मैं एक गैर-वाष्पशील मेमोरी प्रबंधक विकसित करता हूं।


2

सी दृढ़ता से टाइप नहीं किया गया है। एक मानक सी कंपाइलर सरणी सीमा की जाँच नहीं करेगा। दूसरी बात यह है कि C में एक सरणी कुछ भी नहीं है, लेकिन मेमोरी और इंडेक्सिंग का एक सन्निहित ब्लॉक 0 पर शुरू होता है, इसलिए -1 का एक इंडेक्स वह है जो कुछ भी बिट-पैटर्न से पहले है a[0]

अन्य भाषाएं नकारात्मक सूचकांकों का अच्छे तरीके से फायदा उठाती हैं। पायथन में, a[-1]अंतिम तत्व a[-2]को वापस करेगा, दूसरे-से-अंतिम तत्व को वापस करेगा और इसी तरह।


2
कैसे मजबूत टाइपिंग और सरणी सूचकांक संबंधित हैं? क्या ऐसे भी प्रकार के साथ भाषाएँ होती हैं जहाँ पर सरणी सूचकांकों का होना ज़रूरी है?
राफेल

@ राफेल जहां तक ​​मुझे पता है, मजबूत टाइपिंग का मतलब है कि टाइप एरर पकड़े जाते हैं। एक सरणी एक प्रकार है, IndexOutOfBounds एक त्रुटि है इसलिए जोरदार टाइप की गई भाषा में यह रिपोर्ट किया जाएगा, सी में यह नहीं होगा। मेरा मतलब यही था।
सादष्टमी

मुझे पता है कि भाषाओं में, सरणी सूचक प्रकार के होते हैं int, इसलिए a[-5], और, आमतौर पर, int i; ... a[i] = ...;सही प्रकार से टाइप किए जाते हैं। सूचकांक त्रुटियों को केवल रनटाइम पर पता लगाया जाता है। बेशक, एक चतुर संकलक कुछ उल्लंघनों का पता लगा सकता है ।
राफेल

@Raphael मैं संपूर्ण डेटा प्रकार के बारे में बात कर रहा हूँ, सूचकांक प्रकार नहीं। यह बताता है कि C उपयोगकर्ताओं को [-5] लिखने की अनुमति क्यों देता है। हाँ, -5 सही सूचकांक प्रकार है लेकिन यह सीमा से बाहर है और यह एक त्रुटि है। मेरे उत्तर में संकलन या रनटाइम प्रकार की जाँच का कोई उल्लेख नहीं है।
सादष्टमी

1

सरल शब्दों में:

C में सभी चर (सरणियों सहित) मेमोरी में संग्रहीत हैं। मान लीजिए कि आपके पास "मेमोरी" के 14 बाइट्स हैं और आप निम्नलिखित को इनिशियलाइज़ करते हैं:

int a=0;
int array1[6] = {0, 1, 2, 3, 4, 5};

इसके अलावा, 2 बाइट्स के रूप में एक इंट के आकार पर विचार करें। फिर, काल्पनिक रूप से, मेमोरी के पहले 2 बाइट्स में पूर्णांक को सहेजा जाएगा। अगले 2 बाइट्स में सरणी की पहली स्थिति का पूर्णांक सहेजा जाएगा (इसका मतलब है कि सरणी [0])।

फिर, जब आप कहते हैं कि सरणी [-1] स्मृति में सहेजे गए पूर्णांक का उल्लेख करने जैसा है, जो कि सरणी [0] से ठीक पहले है, जो कि हमारे काल्पनिक रूप से पूर्णांक है। वास्तव में, यह बिल्कुल वैसा नहीं है जैसा कि चर स्मृति में संग्रहीत किया जाता है।


0
//:Example of negative index:
//:A memory pool with a heap and a stack:

unsigned char memory_pool[64] = {0};

unsigned char* stack = &( memory_pool[ 64 - 1] );
unsigned char* heap  = &( memory_pool[ 0     ] );

int stack_index =    0;
int  heap_index =    0;

//:reserve 4 bytes on stack:
stack_index += 4;

//:reserve 8 bytes on heap:
heap_index  += 8;

//:Read back all reserved memory from stack:
for( int i = 0; i < stack_index; i++ ){
    unsigned char c = stack[ 0 - i ];
    //:do something with c
};;
//:Read back all reserved memory from heap:
for( int i = 0; i < heap_index; i++ ){
    unsigned char c = heap[ 0 + i ];
    //:do something with c
};;

CS.SE में आपका स्वागत है! हम उन उत्तरों की तलाश में हैं जो स्पष्टीकरण या पढ़ने के विवरण के साथ आते हैं। हम एक कोडिंग साइट नहीं हैं, और हम ऐसे उत्तर नहीं चाहते हैं जो कोड के एक ब्लॉक हैं। आप इस पर विचार कर सकते हैं कि क्या आप इस तरह की जानकारी प्रदान करने के लिए अपने उत्तर को संपादित कर सकते हैं। धन्यवाद!
डीडब्ल्यू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.