... बस आवंटित सीमा के बाहर एक सूचक decrementing मेरे लिए बहुत ही डरावना लगता है। क्या यह "अनुमति" सी में व्यवहार है?
अनुमति है? हाँ। अच्छा विचार? आमतौर पर नहीं।
सी विधानसभा भाषा के लिए एक आशुलिपि है, और विधानसभा भाषा में कोई संकेत नहीं हैं, बस स्मृति पते हैं। C के पॉइंटर्स मेमोरी एड्रेस हैं जो अंकगणित के अधीन होने पर वे जो इंगित करते हैं उसके आकार के हिसाब से बढ़ने या घटने का एक पक्ष व्यवहार है। यह सिंटैक्स दृष्टिकोण से निम्नलिखित को ठीक बनाता है:
double *p = (double *)0xdeadbeef;
--p; // p == 0xdeadbee7, assuming sizeof(double) == 8.
double d = p[0];
Arrays वास्तव में C में एक चीज नहीं है; वे सिर्फ स्मृति की सन्निहित सीमाओं की ओर संकेत करते हैं जो सरणियों की तरह व्यवहार करते हैं। []
ऑपरेटर सूचक अंकगणित कर रहे हैं और अपसंदर्भन, तो के लिए एक आशुलिपि है a[x]
साधन वास्तव में *(a + x)
।
ऐसे कुछ मैं / हे की एक जोड़ी होने डिवाइस के रूप में ऊपर करने के लिए वैध कारण हैं, double
में मैप किया रों 0xdeadbee7
और 0xdeadbeef
। बहुत कम कार्यक्रमों को ऐसा करने की आवश्यकता होगी।
जब आप किसी चीज़ का पता बनाते हैं, जैसे कि &
ऑपरेटर या कॉलिंग का उपयोग करके malloc()
, आप मूल पॉइंटर को अक्षुण्ण रखना चाहते हैं तो आप जानते हैं कि यह जो इंगित करता है वह वास्तव में कुछ मान्य है। पॉइंटर को कम करने का अर्थ है कि कुछ गलत कोड कोड इसे निष्क्रिय करने का प्रयास कर सकते हैं, गलत परिणाम प्राप्त कर सकते हैं, कुछ को क्लोब कर सकते हैं या, आपके पर्यावरण के आधार पर, एक विभाजन उल्लंघन कर सकते हैं। यह विशेष रूप से सच है malloc()
, क्योंकि आपने free()
मूल मूल्य को पारित करने के लिए याद रखने के लिए कॉल करने का बोझ डाल दिया है, न कि कुछ बदला हुआ संस्करण, जिससे सारी बिल्ली ढीली हो जाएगी।
यदि आपको C में 1-आधारित सरणियों की आवश्यकता है, तो आप इसे एक अतिरिक्त तत्व को आवंटित करने की कीमत पर सुरक्षित रूप से कर सकते हैं जिसका उपयोग कभी नहीं किया जाएगा:
double *array_create(size_t size) {
// Wasting one element, so don't allow it to be full-sized
assert(size < SIZE_MAX);
return malloc((size+1) * sizeof(double));
}
inline double array_index(double *array, size_t index) {
assert(array != NULL);
assert(index >= 1); // This is a 1-based array
return array[index];
}
ध्यान दें कि यह ऊपरी सीमा से अधिक की रक्षा करने के लिए कुछ भी नहीं करता है, लेकिन यह काफी आसान है।
परिशिष्ट:
C99 ड्राफ्ट से कुछ अध्याय और आयतें (क्षमा करें, यह सब मेरे साथ लिंक हो सकता है):
§6.5.2.1.1 का कहना है कि सबस्क्रिप्ट ऑपरेटर के साथ प्रयोग किया जाने वाला दूसरा ("अन्य") पूर्णांक प्रकार है। -1
एक पूर्णांक है, और जो p[-1]
वैध बनाता है और इसलिए सूचक को &(p[-1])
वैध बनाता है। इसका मतलब यह नहीं है कि उस स्थान पर मेमोरी एक्सेस करना परिभाषित व्यवहार का उत्पादन करेगा, लेकिन सूचक अभी भी एक वैध सूचक है।
§6.5.2.2 का कहना है कि सरणी सबस्क्रिप्ट ऑपरेटर सूचक के लिए तत्व संख्या को जोड़ने के बराबर का मूल्यांकन करता है, इसलिए p[-1]
इसके बराबर है *(p + (-1))
। फिर भी मान्य है, लेकिन वांछनीय व्यवहार उत्पन्न नहीं कर सकता है।
§6.5.6.8 कहते हैं (जोर मेरा):
जब किसी सूचक का पूर्णांक प्रकार एक सूचक से जोड़ा या घटाया जाता है, तो परिणाम में सूचक ऑपरेटर का प्रकार होता है।
... यदि अभिव्यक्ति एक सरणी वस्तु के भाव तत्व P
को इंगित करता है i
, तो अभिव्यक्तियाँ (P)+N
(समतुल्य N+(P)
) , और (P)-N
(जहां N
मूल्य है n
) क्रमशः, वस्तु वस्तु के i+n
-th और
i−n
-th तत्वों को इंगित करता है , बशर्ते कि वे मौजूद हों ।
इसका मतलब है कि सूचक अंकगणित के परिणामों को एक सरणी में एक तत्व पर इंगित करना है। यह नहीं कहता है कि अंकगणित को एक ही बार में किया जाना है। इसलिए:
double a[20];
// This points to element 9 of a; behavior is defined.
double d = a[-1 + 10];
double *p = a - 1; // This is just a pointer. No dereferencing.
double e = p[0]; // Does not point at any element of a; behavior is undefined.
double f = p[1]; // Points at element 0 of a; behavior is defined.
क्या मैं इस तरह से काम करने की सलाह देता हूं? मैं नहीं, और मेरा जवाब क्यों बताता है।