c - अंतिम आइटम से परे सरणी पॉइंटर को बढ़ाना




arrays pointers (4)

C, Array Bounds के लिए जाँच नहीं करता है। तो भले ही आप किसी सरणी तक पहुँच से परे हो, जो कि घोषित है, यह कोई त्रुटि नहीं देगा। मेरे हिसाब से आपके सवालों के जवाब:

  1. कोई संख्या विशुद्ध रूप से कचरा मूल्य नहीं है।
  2. अंतिम संख्या कुछ भी हो सकती है (कचरा शून्य सहित)। आईएसओ सी मानक के अनुसार इसे अपरिभाषित व्यवहार कहा जाता है।
  3. नहीं, यह नहीं होना चाहिए! लेकिन C उस समय की भाषा है जब कंपाइलर धीमे थे और यहां तक ​​कि असेंबली में 3-4 निर्देशों को सहेजने का भी बहुत मतलब था!

मुझे C प्रोग्रामिंग और एरे पॉइंटर्स के साथ थोड़ा मज़ा आ रहा था।

क्या कोई समझा सकता है कि जब मैं सरणी के आकार से परे एक सरणी सूचक को आगे बढ़ाता हूं तो क्या हो रहा है?

ऐसा लगता है कि मैं मेमोरी सेल तक पहुंच रहा हूं जो सीधे सरणी के बाद है, लेकिन मैं सिर्फ यकीन करना चाहता हूं।

  1. क्या इन नंबरों का कोई मतलब है?
  2. अंतिम संख्या एक शून्य क्यों है?
  3. क्या कोई प्रोग्राम ऐसी मेमोरी को एक्सेस करने में सक्षम होना चाहिए जिसे उसने आवंटित नहीं किया है?

कितने सारे सवाल!

int arr[] = { 1, 2, 3, 4, 5 };
int *xPtr = arr;

for(int i = 0; i < 10; i++) {
    printf("current pointer is %d\n", *xPtr++);
}

का परिणाम:

current pointer is 1
current pointer is 2
current pointer is 3
current pointer is 4
current pointer is 5
current pointer is 0
current pointer is 127926431
current pointer is -759946469
current pointer is -492049712
current pointer is 32766

यह एकमात्र तरीका था जो मुझे सरणी के माध्यम से ठीक से पुनरावृत्त करने के लिए मिला। क्या ये सही है?

int arraySize = sizeof(arr) / sizeof(int);
for(int i = 0; i < arraySize; i++) {
    printf("current pointer is %d\n", *xPtr++);
}

का परिणाम:

current pointer is 1
current pointer is 2
current pointer is 3
current pointer is 4
current pointer is 5

आप सरणी के बाहर मेमोरी एक्सेस कर रहे हैं। ऐरे में सिर्फ 5 तत्व हैं, और आप पॉइंटर को उस से परे बढ़ाते हैं, और इसे हटाते हैं। यहां वास्तव में दो प्रकार की बुरी चीजें हैं: आप सरणी के बाहर डिफ्रेंसिंग कर रहे हैं, लेकिन आप सरणी के अंत से परे एक कदम से अधिक सूचक भी बढ़ा रहे हैं। न ही अनुमति है।

यह अपरिभाषित व्यवहार है, इसलिए कुछ भी हो सकता है। इस मामले में ऐसा लगता है कि आप सरणी के बाद केवल मेमोरी सामग्री प्राप्त कर रहे हैं, जिसे किलों के रूप में व्याख्या किया गया है। आपके C प्रोग्राम के संदर्भ में, वे केवल कचरा मूल्य हैं, क्योंकि एक बार जब आप C में अपरिभाषित व्यवहार करते हैं, तो सभी दांव बंद हो जाते हैं, प्रोग्राम क्रैश या खराब हो सकता है।

यदि आप किसी ऐसे प्रोग्राम का अर्थ बनाना चाहते हैं जिसमें यूबी है, तो आप इसे संकलित करेंगे, फिर उस विशेष संकलन के असेंबली कोड को देखें। बस ध्यान दें कि अगली बार जब आप इसे संकलित करते हैं, तो परिणाम भिन्न हो सकता है (कंपाइलर स्विच, कंपाइलर या लाइब्रेरी अपडेट, विभिन्न कंप्यूटर ...), और नया असेंबली कोड पूरी तरह से अलग व्यवहार हो सकता है (क्योंकि C कोड UB था)। आम तौर पर यह उपयोगी नहीं है, यूबी यूबी है और यह शायद ही कभी कोशिश करता है और इसके बारे में तर्क देता है कि यह क्या करता है।

C की कोई सरणी सीमा जाँच नहीं है, इसलिए C संकलक कोई जाँच नहीं करता है। मेमोरी सुरक्षा के साथ एक आधुनिक पीसी ऑपरेटिंग सिस्टम में, ओएस प्रोग्राम को मार देगा यदि आप उस मेमोरी को एक्सेस करने की कोशिश करते हैं जो उसे नहीं दी गई है, लेकिन इसमें मोटे रिज़ॉल्यूशन (उदाहरण के लिए 4 केबी पेज) हैं, और बहुत सारी मेमोरी हो सकती है वैसे भी आपके कार्यक्रम से संबंधित है, इसलिए OS सरणी के बाद मेगाबाइट के लिए कुछ भी बुरा नहीं देख सकता है।

दूसरा संस्करण अच्छा लग रहा है। बस याद रखें कि sizeof केवल वास्तविक सरणियों के लिए काम करता है, न कि संकेत के लिए, और न ही कार्यों के सरणी मापदंडों के लिए (क्योंकि वे वास्तव में संकेत हैं, वाक्यविन्यास के बावजूद सरणियाँ नहीं हैं)।


जब आप सूचक को सरणी के आकार से परे बढ़ाते हैं, तो हाँ, आप सरणी के ठीक बाद मेमोरी एक्सेस कर रहे हैं। इसमें कचरा मूल्य नामक कोई भी यादृच्छिक मूल्य शामिल होगा।

ये कचरा मान आपके कार्यक्रम में किसी काम के नहीं हैं और आपको अपने उत्तर में दिए गए लूप के लिए नीचे दिए गए उपयोग से इसे एक्सेस करने से बचना चाहिए:

int arraySize = sizeof(arr) / sizeof(int);
for(int i = 0; i < arraySize; i++)
{ 
      printf("current pointer is %d\n", *xPtr++); 
}

इन मूल्यों का कोई मतलब नहीं है। आपके द्वारा इसे एक्सेस करने से पहले वे केवल वे मान हैं जो पहले से ही उस विशेष मेमोरी स्थान में संग्रहीत थे।

मुझे एक उदाहरण के माध्यम से चलते हैं। एक 2D सरणी और इसे इंगित करने वाले एक सूचक पर विचार करें

int a[2][2];
int *p = &a[0][0];

अब, सूचकांकों पर सावधानीपूर्वक विचार करें। यदि आप p+0 प्रयास करते हैं, तो यह a[0][0] को इंगित करेगा, p+1 a[0][1] को इंगित करेगा। लेकिन अगर आप p+2 कोशिश करते हैं तो यह a[1][0] इशारा करेगा क्योंकि यह सिर्फ अगली मेमोरी लोकेशन है।

और p+3 से परे अर्थात p+4 सभी मान कचरा होंगे।


यह निर्भर करता है कि कोई ऐरे को कहां घोषित करता है (एरे का अधिक सटीक भंडारण स्थान)। यदि आपने किसी भी प्रकार के ऐरे को बिना वैश्वीकरण या स्थैतिक के रूप में घोषित किया है, तो डिफ़ॉल्ट रूप से इसे शून्य पर आरंभीकृत किया जाता है; अन्यथा, यदि आप इसे किसी भी फ़ंक्शन के अंदर घोषित करते हैं, जैसे कि ऑटो बिना इनिशियलाइज़ेशन के, तो इसमें कचरा मूल्य शामिल होगा। यहां आपके प्रोग्राम में, जब सरणी सीमा से बाहर मेमोरी में किसी स्थान पर पहुंच जाता है, तो प्रोग्राम को मिलने वाला मूल्य एक कचरा मूल्य है। क्योंकि डिफ़ॉल्ट रूप से प्रत्येक मेमोरी लोकेशन में कचरा मूल्य होता है। एक सरणी को आरम्भ करने पर स्मृति का एक खंड आपके द्वारा प्रदत्त मूल्यों के साथ नियत हो जाता है। दूसरी बात यह है कि पुनरावृति सरणी का कोई सबसे अच्छा नहीं है; यह पूरी तरह से आप पर निर्भर करता है।

एक पॉइंटर को बढ़ाने पर, यह उस ऑब्जेक्ट के आकार को बढ़ाता है जो इसे इंगित कर रहा है, सरणी में अगले तत्व की ओर इशारा करता है। जैसे उदहारण के लिए:

data_type  arr[10];

पॉइंटर की वृद्धि साइज़ोफ़ (data_type) द्वारा होगी। C तक पहुँचने में असंबद्ध स्मृति अपवाद / चेतावनी फेंक सकती है।





pointers