2010-06-29 9 views
11

संभव डुप्लिकेट:
Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?क्या मैं एक सरणी के एक-अतीत के अंत तत्व का पता ले सकता हूं?

int array[10]; 

int* a = array + 10; // well-defined 
int* b = &array[10]; // not sure... 

अंतिम पंक्ति मान्य नहीं है या नहीं?

+2

दिग्गज का शिकार http://stackoverflow.com/questions/988158/ –

+0

@ जोहान्स - आप सही हैं, बंद करने के लिए मतदान कर रहे हैं - एक-एक-अतीत-अंत-अंत-तत्व-तत्व-के माध्यम से-सबस्क्रिप्ट-कानूनी-द्वारा-0 [email protected] जोहान्स - आप सही हैं, बंद करने के लिए मतदान कर रहे हैं। – Omnifarious

उत्तर

19

हां, आप एक सरणी के अंत से एक पता ले सकते हैं, लेकिन आप इसे अस्वीकार नहीं कर सकते हैं। 10 आइटमों की आपकी सरणी के लिए, array+10 काम करेगा। यह कुछ बार तर्क दिया गया है (समिति द्वारा, दूसरों के बीच) चाहे &array[10] वास्तव में अनिर्धारित व्यवहार का कारण बनता है या नहीं (और यदि ऐसा होता है, चाहे वह वास्तव में होना चाहिए)। इसके साथ नीचे की रेखा यह है कि कम से कम मौजूदा मानकों (सी और सी ++ दोनों) के अनुसार यह आधिकारिक तौर पर अपरिभाषित व्यवहार का कारण बनता है, लेकिन यदि कोई एकल कंपाइलर है जिसके लिए यह वास्तव में काम नहीं करता है, तो किसी भी तर्क में से कोई भी सक्षम नहीं है इसे खोजने या उद्धृत करने के लिए।

संपादित करें: के लिए एक बार मेरी स्मृति आधा सही था - यह (का हिस्सा) समिति के लिए एक आधिकारिक Defect Report, और कम से कम कुछ समिति के सदस्यों था (जैसे, टॉम बेर) सोचा शब्दों तो यह होगा बदल दिया गया था अपरिभाषित व्यवहार का कारण नहीं है। ओटीओएच, डीआर 2000 से तारीखें हैं, और स्थिति अभी भी "ड्राफ्टिंग" है, इसलिए यह सवाल उठाने के लिए खुला है कि यह वास्तव में तय है या कभी भी होने की संभावना है (मैंने पता लगाने के लिए एन 30 9 0/30 9 2 को देखा नहीं है)।

सी 99 में, हालांकि, यह स्पष्ट रूप से अपरिभाषित व्यवहार है।

+1

अच्छा जवाब। इतिहास के शायद एक दिलचस्प बिंदु के रूप में, मैंने वास्तव में एक सी संकलक देखा जो सही ढंग से dereference और सरणी [एन] में विफल रहा। यह एचपी -1000 मुख्य फ्रेम पर एचपी आरटीई पर था।इसने मेरी सरणी के ठीक ऊपर एक स्मृति "बाड़" निर्धारित की थी, इसलिए संदर्भ पता प्रोग्राम के पता स्थान में मौजूद नहीं था। यह 1 9 8 9 सी मानक से पहले भी था, इसलिए मुझे लगता है कि यह कहना सुरक्षित है कि यह कंपाइलर अब नहीं है। –

+0

उस डीआर की भाषा N3092 में नहीं है। हालांकि मैं उन्हें अभी नहीं ढूंढ पा रहा हूं, ऐसे कई _closed_ DRs हैं जो प्रस्तावित संकल्प में "खाली लालू" भाषा पर भरोसा करते हैं ... –

1

नहीं। यह अनिर्धारित है। array[10] की मात्रा *(array + 10) है। दूसरे शब्दों में, आपने एक अमान्य सूचक का वर्णन किया है।

+3

लेकिन उन्होंने इसे अस्वीकार नहीं किया ... –

+1

@clmh इस बात पर एक निश्चित बहस है कि '& * p' तकनीकी रूप से नो-ऑप का गठन करता है, या किसी पते के बाद एक बहिष्कार होता है। –

+1

'और सरणी [10] 'कानूनी है, और तत्व को कम नहीं करता है। –

2

array[10]*(array + 10) (और यह भी बराबर करने के लिए 10[array]) के बराबर *(array+10) से * को हटाने की तरह तो &array[10] कार्य करता है,। किसी भी सभ्य संकलक को एक ही कोड (और एक ही चेतावनी) उत्सर्जित करना चाहिए।

8

जैसा कि अन्य उत्तरों संकेत दिए गए हैं, अभिव्यक्ति array[10]*(array + 10) के बराबर है, जो परिणामस्वरूप सरणी के अंत से पहले तत्व की एक अनिर्धारित डीरफ्रेंसिंग दिखाई देगी। हालांकि, अभिव्यक्ति &array[10]&*(array + 10) के बराबर है, और C99 मानक स्पष्ट (6.5.3.2 पता और अविवेक ऑपरेटरों) बनाता है:

एकल & ऑपरेटर अपनी संकार्य का पता देता है। यदि ऑपरेंड में '' टाइप 'टाइप होता है, तो परिणाम में टाइप करने के लिए' पॉइंटर टाइप 'होता है। यदि ऑपरेंड एक unary * ऑपरेटर का नतीजा है, न तो वह ऑपरेटर और न ही & ऑपरेटर का मूल्यांकन किया जाता है और नतीजा यह होता है कि दोनों को छोड़ दिया गया था, सिवाय इसके कि ऑपरेटरों पर बाधाएं अभी भी लागू होती हैं और परिणाम एक अंतराल नहीं होता है। इसी प्रकार, यदि ऑपरेंड [] ऑपरेटर का नतीजा है, न तो & ऑपरेटर और न ही * जो [] द्वारा निहित है, का मूल्यांकन किया गया है और परिणाम यह है कि & ऑपरेटर हटा दिए गए थे और [] ऑपरेटर को + ऑपरेटर में बदल दिया गया था ।

तो, &array[10] के बारे में कुछ भी अपरिभाषित नहीं है - कोई अपरिवर्तनीय संचालन नहीं होता है।

+5

सी 99 सी ++ नहीं है। –

-2

यह वास्तव में उत्तर देने के लिए एक साधारण बात है।

आप जो भी कर रहे हैं वह पॉइंटर गणित है, इसके बारे में कुछ भी अमान्य नहीं है। यदि आप परिणामस्वरूप पॉइंटर्स का किसी भी तरीके से उपयोग करने का प्रयास करते हैं तो इस बात पर निर्भर करता है कि आपकी प्रक्रिया में उस पॉइंटर द्वारा इंगित स्मृति तक पहुंच है या नहीं, और यदि ऐसा है तो इस पर अनुमतियां क्या हैं?

foo.cc:

#include <iostream> 

using namespace std; 
int main() { 
     int array[10]; 
     int *a = array + 10; 
     int *b = &array[10]; 
     int *c = &array[3000]; 

     cerr << "Pointers values are: " << a << " " << b << " " << c << endl; 
     return 0; 
} 

संकलित करने के लिए:

g++ -Werror -Wall foo.cc -o foo 

कोई चेतावनी नहीं उपज चाहिए क्योंकि पूर्णांक * ख = & सरणी [10] वैध

असल में तो है पॉइंटर गणित के बारे में कुछ इंगित करने के लिए मेरे द्वारा जोड़ा गया अगला लाइन है।

न केवल संकलन foo जाएगा, यह बिना किसी अवरोध के चलेंगे:

./foo 
    Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20 

असल सारणी वाक्य-विन्यास foo [IDX] है शॉर्टकट और सूचक गणित के स्वच्छ प्रतिनिधित्व।

यदि सी 99 के बारे में कुछ भ्रम है, तो मानक किसी भी तरह से और अच्छी तरह से परिभाषित इस गणित को प्रभावित नहीं करता है।

C99 में एक ही बात:

#include <stdio.h> 

int main() { 
     int array[10]; 
     int *a = array + 10; 
     int *b = &array[10]; 
     int *c = &array[3000]; 

     fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c); 
     return 0; 
} 

तब:

gcc -std=c99 -Wall -Werror -o foo foo.c 

./foo 

आउटपुट:

Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180 
संबंधित मुद्दे

 संबंधित मुद्दे