2011-01-06 22 views
5

का उपयोग करके संरचना तत्वों तक पहुंचने पर मुझे आश्चर्य हुआ जब निम्न प्रोग्राम क्रैश नहीं हुआ।पॉइंटर्स

typedef struct _x { 
    int a; 
    char b; 
    int c; 
} x; 

main() { 
    x *ptr = 0; 
    char *d = &ptr->b; 
} 

मेरी समझ के अनुसार -> ऑपरेटर & ऑपरेटर साथ-साथ उसका पूर्वता है। तो मुझे उम्मीद है कि जब हम नल पॉइंटर tr को कम करने की कोशिश करेंगे तो प्रोग्राम नीचे दिए गए कथन पर दुर्घटनाग्रस्त हो जाएगा।

char *d = &ptr->b; 

लेकिन कथन &ptr->b एक मान्य पते का मूल्यांकन करता है। क्या कोई कृपया बता सकता है कि मैं कहां गलत हूं?

+0

यह किसी भी तरह से 'ऑफसेटोफ़' मैक्रो के समान है। – ruslik

उत्तर

2

&ptr->b == sizeof(int), कि _x.a के बाद _x भीतर b की भरपाई पता *((x*)0) के सापेक्ष (प्रकार int की है) का मतलब है। 4 (32 बिट आर्किटेक्चर के लिए विशिष्ट) का ऑफसेट d पॉइंटर के भीतर सहेजा गया है। सीजी-गलती प्राप्त करने के लिए आपको d तक पहुंच प्राप्त करनी होगी।

4

आपका कोड क्रैश नहीं होने का कारण यह है कि आपने वास्तव में पॉइंटर को अस्वीकार नहीं किया था। ध्यान दें कि अभिव्यक्ति

&ptr->b 

वास्तव में ptr या ptr->b की सामग्री को लोड करने का प्रयास नहीं करता है। इसके बजाए, यह सिर्फ उस पते का संग्रह करता है जहां यह स्मृति में स्थित है। आप जो प्राप्त करेंगे, वह एक सूचक है जहां पर ऑब्जेक्ट के b फ़ील्ड को इंगित किया जाना चाहिए। यह पिछले पते 0 के कुछ बाइट्स होगा, इसलिए आपके द्वारा बनाए गए पॉइंटर को डिफ्रेंस करने से सीगफॉल्ट होगा।

2

किसी पते की गणना करने के लिए स्मृति तक पहुंच की आवश्यकता नहीं है। &ptr->b का अर्थ है "मुझे ptr द्वारा इंगित संरचना के b फ़ील्ड का पता दें।" ऐसा करने के लिए उस स्मृति स्थान में जो कुछ भी संग्रहीत किया जा सकता है उसे देखने की आवश्यकता नहीं है।

संरचना के बजाए सरणी को अनुक्रमणित करने के बारे में सोचने में मददगार हो सकता है। सी ptr[5] को *(ptr + 5) के बराबर परिभाषित करता है, जिसका अर्थ है कि &(ptr[5])&(*(ptr + 5)) जैसा ही है। अब यह देखना आसान है कि & और * "रद्द करें" और आपको (ptr + 5) के साथ छोड़ दें, जिसमें केवल एक सूचक वृद्धि शामिल है, न कि स्मृति से लोड।

सी इसे थोड़ा बादल बनाता है क्योंकि यह राजस्व से अंतराल को अलग करता है। यही है, एक अभिव्यक्ति जो स्मृति को संदर्भित करती है, अभिव्यक्ति के बाईं ओर अलग-अलग तरीके से व्यवहार की जाती है। x = y; जैसे बयान को देखते हुए, एक सी संकलक y के पते से एक मान लोड करेगा, और इसे x के पते पर संग्रहीत करेगा। यह भेद है: y निहित रूप से संदर्भित है, लेकिन x नहीं है।

5

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

लेकिन किसी भी मामले में, आपके प्रोग्राम का व्यवहार अपरिभाषित है।और नहीं, यह एक "मान्य पता" उत्पन्न नहीं करता है जैसा कि आप गलत तरीके से विश्वास करते हैं। एक संख्यात्मक पता जो स्मृति में किसी स्थान से मेल खाता है जहां कोई ऑब्जेक्ट मौजूद नहीं है मान्य नहीं है (निश्चित रूप से शून्य सूचक मान के अपवाद के साथ)।

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