क्या सी में नकारात्मक सरणी अनुक्रमित की अनुमति है?


115

मैं अभी कुछ कोड पढ़ रहा था और पाया कि वह व्यक्ति arr[-2]2 तत्व तक पहुँचने से पहले उपयोग कर रहा था arr, जैसे:

|a|b|c|d|e|f|g|
       ^------------ arr[0]
         ^---------- arr[1]
   ^---------------- arr[-2]

क्या इसकी अनुमति है?

मुझे पता है कि arr[x]जैसा है वैसा ही है *(arr + x)। तो arr[-2]है *(arr - 2)जो ठीक लगता है,। तुम क्या सोचते हो?

जवाबों:


168

वह सही है। C99 से C6.5.2.1 / 2:

सबस्क्रिप्ट ऑपरेटर का [de nition] यह है कि E1 [E2] (* (E1) + (E2)) के समान है।

कोई जादू नहीं है। यह एक 1-1 तुल्यता है। हमेशा की तरह जब एक पॉइंटर (*) को डिफाइन किया जाता है, तो आपको यह सुनिश्चित करने की आवश्यकता है कि यह एक वैध पते की ओर इशारा कर रहा है।


2
यह भी ध्यान दें कि UB पाने के लिए आपको पॉइंटर को डिरेल करने की आवश्यकता नहीं है। somearray-2जब तक परिणाम somearray1 के प्रारंभ से लेकर उसके अंत तक होता है, तब तक मेरली कंप्यूटिंग अपरिभाषित होती है।
RBerteig

34
पुरानी पुस्तकों में सूचक अंकगणित के लिए []एक वाक्यविन्यास चीनी के रूप में संदर्भित किया गया था । शुरुआती लोगों को भ्रमित करने का पसंदीदा तरीका लिखना है 1[arr]- इसके बजाय arr[1]- और उन्हें अनुमान लगाते हुए देखें कि इसका क्या मतलब है।
डमी 00001

4
64 बिट सिस्टम (LP64) पर क्या होता है जब आपके पास 32 बिट इंट इंडेक्स होता है जो नकारात्मक है? क्या पता गणना से पहले सूचकांक को 64 बिट हस्ताक्षरित इंट को बढ़ावा दिया जाना चाहिए?
पॉल आर

4
@Paul, §6.5.6 / 8 (एडिटिव ऑपरेटर्स) से, "जब एक एक्सप्रेशन से पूर्णांक प्रकार को जोड़ा या घटाया जाता है, तो परिणाम में पॉइंटर ऑपरेटर का प्रकार होता है। यदि सूचक एक तत्व को इंगित करता है। एक सरणी ऑब्जेक्ट, और सरणी काफी बड़ी है, परिणाम एक तत्व को मूल तत्व से ऑफसेट करता है जैसे कि परिणामी और मूल सरणी तत्वों की सदस्यता का अंतर पूर्णांक अभिव्यक्ति के बराबर होता है। " इसलिए मुझे लगता है कि इसे बढ़ावा दिया जाएगा, और ((E1)+(E2))अपेक्षित मूल्य के साथ (64-बिट) सूचक होगा।
मैथ्यू फ्लेशेन

@ मैथ्यू: इसके लिए धन्यवाद - ऐसा लगता है कि यह काम करना चाहिए क्योंकि किसी को उम्मीद की जा सकती है।
पॉल आर

63

यह केवल तभी मान्य है जब arrएक सूचक है जो एक सरणी या बाद के तत्व में दूसरे तत्व को इंगित करता है। अन्यथा, यह मान्य नहीं है, क्योंकि आप सरणी के सीमा के बाहर स्मृति तक पहुंच रहे होंगे। इसलिए, उदाहरण के लिए, यह गलत होगा:

int arr[10];

int x = arr[-2]; // invalid; out of range

लेकिन यह ठीक होगा:

int arr[10];
int* p = &arr[2];

int x = p[-2]; // valid:  accesses arr[0]

हालांकि, एक नकारात्मक सबस्क्रिप्ट का उपयोग करना असामान्य है।


मैं अब तक यह नहीं कहूंगा कि यह अवैध है, बस संभावित रूप से गड़बड़ है
मैट जॉइनर

13
@ मैट: पहले उदाहरण में कोड अपरिभाषित व्यवहार देता है।
जेम्स मैकनेलिस

5
यह अमान्य है। सी मानक द्वारा, यह स्पष्ट रूप से अपरिभाषित व्यवहार करता है। दूसरी ओर, यदि int arr[10];इससे पहले अन्य तत्वों के साथ एक संरचना का हिस्सा थे , तो arr[-2]संभावित रूप से अच्छी तरह से परिभाषित किया जा सकता है, और आप यह निर्धारित कर सकते हैं कि यह किस पर आधारित है offsetof, आदि
R .. GitHub STOP HELPING ICE

4
इसे K & R धारा 5.3 में मिला, अंत के पास: If one is sure that the elements exist, it is also possible to index backwards in an array; p[-1], p[-2], and so on are syntactically legal, and refer to the elements that immediately precede p[0]. Of course, it is illegal to refer to objects that are not within the array bounds.फिर भी, आपका उदाहरण मुझे इसे समझने में मदद करने में बेहतर है। धन्यवाद!
Qiang जू

4
थ्रेड नेक्रोमेंसी के लिए क्षमा करें, लेकिन मैं सिर्फ प्यार करता हूं कि कैसे और आर "अवैध" के रूप में अस्पष्ट हैं। अंतिम वाक्य यह ध्वनि करता है जैसे आउट-ऑफ-बाउंड एक्सेस एक संकलन त्रुटि फेंकते हैं। वह किताब शुरुआती लोगों के लिए ज़हर है।
मार्टिन

12

मुझे ठीक लगता है। यह एक दुर्लभ मामला होगा कि आपको कानूनी रूप से इसकी आवश्यकता होगी।


9
यह दुर्लभ नहीं है - यह बहुत उपयोगी है जैसे पड़ोस के संचालकों के साथ छवि प्रसंस्करण।
पॉल आर

मुझे बस इसका उपयोग करने की आवश्यकता थी क्योंकि मैं एक स्टैक और ढेर [संरचना / डिज़ाइन] के साथ एक मेमोरी पूल बना रहा हूं। स्टैक उच्च मेमोरी पतों की ओर बढ़ता है, कम मेमोरी पतों की ओर बढ़ता ढेर। बीच में मिलना।
जेएमआई मैडिसन

8

शायद जो arrथा वह सरणी के मध्य की ओर इशारा कर रहा था, इसलिए arr[-2]सीमा से बाहर न जाकर मूल सरणी में किसी चीज़ की ओर इशारा करता है।


7

मुझे यकीन नहीं है कि यह कितना विश्वसनीय है, लेकिन मैं सिर्फ 64-बिट सिस्टम (LP64 संभवतः) पर नकारात्मक सरणी सूचकांकों के बारे में निम्नलिखित चेतावनी पढ़ता हूं: http://www.devx.com/tips/Tip/41349

लेखक यह कहता हुआ प्रतीत होता है कि 64 बिट एड्रेसिंग के साथ 32 बिट इंट सरणी इंडेक्स खराब एड्रेस गणनाओं के परिणामस्वरूप हो सकता है जब तक कि सरणी इंडेक्स को 64 बिट्स (जैसे कि एक ptrdiff_t कास्ट के माध्यम से) को बढ़ावा नहीं दिया जाता है। मैंने वास्तव में gcc 4.1.0 के पावरपीसी संस्करण के साथ उसकी प्रकृति का एक बग देखा है, लेकिन मुझे नहीं पता कि यह एक कंपाइलर बग है (यानी C99 मानक के अनुसार काम करना चाहिए) या सही व्यवहार (यानी इंडेक्स के लिए 64 की आवश्यकता है सही व्यवहार के लिए बिट्स)?


3
यह एक कंपाइलर बग की तरह लगता है।
tbleher

2

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

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

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

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

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

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

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

यह मुझे 990 के स्थान पर वस्तु लौटाएगा। इस तर्क से हम C में Array में ऋणात्मक अनुक्रमणिकाओं तक पहुँच सकते हैं।


2

इस बारे में कि कोई व्यक्ति नकारात्मक अनुक्रमित का उपयोग क्यों करना चाहता है, मैंने उन्हें दो संदर्भों में उपयोग किया है:

  1. कॉम्बीनेटरियल नंबरों की एक तालिका होने से जो आपको कंघी बताता है [1] [- 1] = 0; टेबल पर पहुंचने से पहले आप हमेशा इंडेक्स की जांच कर सकते हैं, लेकिन इस तरह से कोड क्लीनर दिखता है और तेजी से निष्पादित होता है।

  2. एक मेज की शुरुआत में एक सेंटिनल डालना। उदाहरण के लिए, आप कुछ का उपयोग करना चाहते हैं

     while (x < a[i]) i--;

लेकिन फिर आपको यह भी जांचना चाहिए कि iक्या सकारात्मक है।
समाधान: यह इतना है कि बनाने के a[-1]है -DBLE_MAX, ताकि x&lt;a[-1]हमेशा गलत हो जाएगा।


0
#include <stdio.h>

int main() // negative index
{ 
    int i = 1, a[5] = {10, 20, 30, 40, 50};
    int* mid = &a[5]; //legal;address,not element there
    for(; i < 6; ++i)
    printf(" mid[ %d ] = %d;", -i, mid[-i]);
}

1
हालांकि यह कोड प्रश्न का उत्तर दे सकता है, क्यों और / या इस कोड के उत्तर के बारे में अतिरिक्त संदर्भ प्रदान करने से प्रश्न इसके दीर्घकालिक मूल्य में सुधार करता है।
β.βοιτ.βε

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