जब भी मैं लटकने वाले पॉइंटर्स लेख पढ़ता हूं। मैं यहां संभावित जोखिम का अनुमान नहीं लगा सकता। नीचे दिए गए कोड में क्या समस्या है यदि मैं पॉइंटर को इनिशियलाइज़ नहीं करता हूं, या मैं मॉलॉक का पता लगाने के बाद NULL को ptr असाइन नहीं करता हूं? यह क्यों लटकता है, यहाँ क्या जोखिम है?

int main()
{
    int *ptr;      //what is risk here?
    
    ptr = (int *)malloc(sizeof(int));

    // After below free call, ptr becomes a
    // dangling pointer
    free(ptr);
    
    
    //ptr = NULL;           //what is risk here if i do not assign NULL?
}
-1
Ravi 17 जुलाई 2021, 12:22

3 जवाब

सबसे बढ़िया उत्तर

जोखिम दिखाए गए कोड में नहीं है, जोखिम रखरखाव, संशोधन और पुन: उपयोग के बाद कोड में है। या "कार्गो-पंथ" में विरोधी पैटर्न की नकल। उदाहरण के लिए यदि आपने आरंभिक ptr घोषणा और malloc() के बीच बहुत अधिक कोड जोड़ा है, तो यह अब स्पष्ट नहीं हो सकता है कि सूचक अभी तक मान्य नहीं है।

"दुर्घटना से" एक शून्य सूचक को संदर्भित करना आम तौर पर रन-टाइम त्रुटि के रूप में फंस जाएगा, इसलिए परीक्षण और विकास के दौरान पता लगाया जा सकता है और त्रुटि के बिंदु पर रिपोर्ट किया जा सकता है। एक सूचक को संदर्भित करना जो एक वैध पता है, लेकिन कहें कि पुन: उपयोग के लिए ढेर में लौटाए गए ब्लॉक को संदर्भित करता है, इसका कोई तत्काल अवलोकन योग्य प्रभाव नहीं हो सकता है, लेकिन बाद में असंबंधित कोड विफल हो सकता है, संभवतः तैनाती के बाद और अप्रत्याशित तरीकों से - वे बग बहुत हैं ट्रैक करना मुश्किल है।

एक पॉइंटर को डीरेफरेंस करना जिसे बस इनिशियलाइज़ नहीं किया गया है, अपरिभाषित व्यवहार होगा, यह काम करने के लिए प्रकट हो सकता है, यह एक अपवाद को ट्रिगर कर सकता है, यह कोड को कोड में एक असंबंधित स्थान पर विफल होने का कारण बन सकता है - फिर से ऐसे बग कठिन हैं नीचे ट्रैक करें जब तक कि आप इसके लिए पर्याप्त भाग्यशाली न हों कि यह तुरंत विफल हो जाए - यदि यह NULL या एक अमान्य पता उदाहरण के लिए अपवाद को ट्रिगर करता है।

इसके अलावा, "असुरक्षित" कोड के कोई लाभ नहीं हैं:

    int *ptr;      //what is risk here?
    
    ptr = (int *)malloc(sizeof(int));

इस प्रकार सुरक्षित और सरल कोड दोनों पर:

    int* ptr = malloc( sizeof(*ptr) ) ;

इसमें अन्य सुधारों पर ध्यान दें:

  • गंतव्य प्रकार के लिए शून्य-सूचक न डालें,
  • एक स्पष्ट प्रकार के बजाय sizeof ऑब्जेक्ट की ओर इशारा किया (या उसके एक से अधिक) का उपयोग करें।

आधुनिक सी में याद रखें, ब्रेस-ब्लॉक ({...}) की शुरुआत में सभी चर घोषित करने के लिए अब आवश्यक नहीं है - हालांकि आप अभी भी उस विरोधी पैटर्न को भी देखेंगे - इसलिए प्रारंभ न करने के कुछ बहाने हैं तात्कालिकता पर एक उपयोगी मूल्य के साथ सूचक।

1
Clifford 17 जुलाई 2021, 10:42

केवल एक लटकता हुआ सूचक जोखिम होता है यदि आप किसी सूचक का उपयोग करते हैं, जब वह डेटा इंगित करता है जो अब मान्य नहीं है। प्रदान किए गए आपके कोड स्निपेट में ऐसा नहीं है।

यदि आप इसका उपयोग उस समय करते हैं जब यह इंगित करता है कि डेटा अमान्य है (malloc से पहले शुरू नहीं किया गया है या free के बाद लटक रहा है), सभी दांव बंद हैं, यह अपरिभाषित व्यवहार है (यूबी) )

यह भी UB है यदि आप NULL का उपयोग करते हैं जो कि हो सकता है लौटाया जा सकता है यदि आपका malloc विफल हो जाता है, तो आपको हमेशा इसकी जांच करनी चाहिए। और, इस वजह से, इसे NULL पर सेट करने के बाद, यह इंगित करता है कि मेमोरी वैध नहीं है, इससे आपको बिल्कुल भी मदद नहीं मिलेगी। यह उतना ही UB है जितना कि dereference NULL के रूप में यह dereference स्मृति के लिए है जिसे मुक्त किया गया है।

आप अपने कोड को कुछ इस तरह से सुरक्षित बना सकते हैं:

int main(void) {
    int *ptr = malloc(sizeof(int));
    if (ptr == NULL) {
        puts("Could not allocate");
        return 1;
    }

    // safe to use pointer here.
    free(ptr);
    // but not here.
}
2
paxdiablo 17 जुलाई 2021, 09:44
int main()
{
    int *ptr;      //what is risk here?
    
    ptr = (int *)malloc(sizeof(int));

यहां आपके पास 2 जोखिम हैं। पहला यह है कि वास्तविक परियोजना में कोड की इन 2 पंक्तियों के बीच यह एक और कोड हो सकता है। और एक मौका है कि आप (या कोई और जो इस कोड को बनाए रखता है) इस सूचक को प्रारंभ करने से पहले इसे निष्क्रिय करने का प्रयास करेगा।

दूसरा यह है कि मॉलोक का रिटर्न वैल्यू चेक नहीं किया जाता है, इसलिए यदि मॉलोक विफल हो जाता है, तो आपको पता नहीं चलेगा कि यह विफल हो गया है।

free(ptr);


//ptr = NULL;           //what is risk here if i do not assign NULL?

जब आप मुक्त करते हैं() आप वास्तव में स्मृति को "मुक्त" नहीं करते हैं (आप स्मृति के आवंटित हिस्से में सभी बिट्स को '0' पर सेट नहीं करते हैं) तो आप इस स्मृति को "भविष्य में आवंटन में फिर से आवंटित किया जा सकता है" के रूप में चिह्नित करते हैं) । लेकिन आपका पॉइंटर अभी भी मेमोरी के इस हिस्से की ओर इशारा करता है। इसलिए कुछ समय के बाद मेमोरी के इस हिस्से को दूसरे आवंटन के लिए इस्तेमाल किया जा सकता है। कुछ नया डेटा इस चंक में संग्रहीत किया जाएगा (डेटा ओवरराइट किया जाएगा)। और आपका पॉइंटर होगा उस मेमोरी को इंगित करें जो प्रासंगिक डेटा संग्रहीत नहीं करता है। और आप (या लायक - कोई और जो आपकी परियोजना को बनाए रखता है) इस सूचक का उपयोग यह जाने बिना कर सकता है कि वह गैर-प्रासंगिक डेटा की ओर इशारा करता है।

1
Igor_M 17 जुलाई 2021, 16:32