2012-05-21 10 views
8
int main() 
{ 
    char *p; 
    p = (char*) malloc(sizeof(char) * 0); 
    printf("Hello Enter the data without spaces :\n"); 
    scanf("%s",p); 
    printf("The entered string is %s\n",p); 
    //puts(p); 
} 

उपरोक्त कोड को संकलित करने और इसे चलाने पर, प्रोग्राम स्ट्रिंग को पढ़ने में सक्षम है भले ही हमने पॉइंटर पी को 0 बाइट मेमोरी असाइन की हो।मॉलोक का व्यवहार (0)

p = (char*) malloc(0) कथन में वास्तव में क्या होता है?

+5

विषय बंद करें .. लेकिन मॉलोक रिटर्न डालने के लिए यह एक अच्छा अभ्यास नहीं है .. देखें [यह] (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Krishnabhadra

+4

सी आपके द्वारा सौंपा गया बफर ओवर-रनिंग के विरुद्ध आपकी सुरक्षा नहीं करता है - आपको यह करने के लिए सावधान रहना होगा अन्यथा आप किसी और की स्मृति पर टंपल करेंगे। – Rup

+1

संभावित डुप्लिकेट [मैलोक (0) विंडोज में एक गैर-शून्य पता क्यों देता है?] (Http://stackoverflow.com/questions/9723030/why-does-malloc0-return-a-non-null-address- इन-विंडोज़) – Jay

उत्तर

12

यह कार्यान्वयन परिभाषित किया गया है कि malloc() वापस आएगा लेकिन यह उस सूचक का उपयोग करने के लिए अपरिभाषित व्यवहार है। और अनिर्धारित व्यवहार का मतलब है कि बिना किसी दुर्घटना के काम कर रहे कार्यक्रम से सचमुच कुछ भी हो सकता है, सभी सुरक्षित दांव बंद हैं।

C99 मानक:

7.22.3 मेमोरी प्रबंधन कार्यों
पैरा 1:

अनुरोध किया अंतरिक्ष के आकार शून्य है, व्यवहार कार्यान्वयन परिभाषित किया गया है: या तो एक शून्य सूचक वापस आ जाता है, या व्यवहार ऐसा होता है जैसे आकार कुछ nonzero मान थे, सिवाय इसके कि लौटा सूचक का उपयोग किसी ऑब्जेक्ट तक पहुंचने के लिए नहीं किया जाएगा।

+0

लेकिन ध्यान दें कि 'malloc' के परिणाम पर 'हमेशा' कॉल करने के लिए यह हमेशा * ठीक है। –

+1

अलस ने जो लिखा है उसके लिए एक परिशिष्ट - अपरिभाषित व्यवहार में "यह वही करता है जो मुझे लगता है कि यह करना चाहिए, * इस बार *।" अगली बार अलग हो सकता है। एक अलग ओएस पर यह शायद अलग होगा। – cschneid

+2

.. जब तक आप केवल एक बार ऐसा करते हैं। –

0

अलस टिप्पणी के अलावा - क्या होता है: आप स्मृति में कहीं लिखते हैं और वहां से डेटा पुनर्प्राप्त करते हैं। तो आपके सिस्टम और ओएस प्रकार के आधार पर आपको अपवाद मिलता है या केवल कुछ अपरिभाषित व्यवहार

0

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

अपने कोड के अपने संशोधन है:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    char *p; 
    p = malloc(sizeof(char)*0); 
    printf("Hello Enter some without spaces :\n"); 
    scanf("%s",p); 

    char *q; 
    q = malloc(sizeof(char)*0); 
    printf("Hello Enter more data without spaces :\n"); 
    scanf("%s",q); 

    printf("The first string is '%s'\n",p); 
    printf("The second string is '%s'\n",q); 
} 

मेरी पहली सोचा है कि आप तथ्य यह है कि आप केवल एक ही स्मृति स्थान में डेटा पढ़ रहे हैं द्वारा बचाया जा सकता था - अगर आप दो बफ़र्स उपयोग करते हैं, दूसरा पहले के ऊपर लिख सकता है ... इसलिए मैं इनपुट और आउटपुट वर्गों में कोड को तोड़ दिया:

Hello Enter some without spaces : 
asdf 
Hello Enter more data without spaces : 
tutututu 
The first string is 'asdf' 
The second string is 'tutututu' 

पहले बफर ओवरराइट कर दिया गया था, तो हम देखना होगा

The first string is 'tutututu' 
The second string is 'tutututu' 

तो ऐसा नहीं है।

फिर [लेकिन यह कितना डेटा आप प्रत्येक बफर में पैक पर निर्भर करता है ... नीचे देखें], मैं दोनों चर में डेटा की एक पागल राशि चिपकाया:

perl -e 'print "c" x 5000000 . "\n" ' | xsel -i 

(इस के 4 एमबी डाल 'सी कॉपी बफर में)। मैंने इसे पहले और दूसरे स्कैनफ कॉल दोनों में चिपकाया। कार्यक्रम ने इसे विभाजन खंड के बिना लिया।

भले ही मेरे पास सेगमेंटेशन गलती न हो, फिर भी पहला बफर ओवरराइट हो गया। मैं इसे नहीं बता सका क्योंकि स्क्रीन पर इतना डेटा उड़ रहा था।यहाँ कम डेटा के साथ एक रन है:

$ ./foo 
Hello Enter some without spaces : 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
Hello Enter more data without spaces : 
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 
The first string is 'aaaaaaaaaaaa' 
The second string is 'ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' 

aaaaaaaaaaaa के बाद एक छोटे से ग्लिफ़, जिसके कारण मेरी टर्मिनल एक यूनिकोड चरित्र है कि यह प्रदर्शित नहीं कर सकता का प्रतिनिधित्व करता था। यह अधिलेखित डेटा के विशिष्ट है: आपको पता नहीं है कि आपके डेटा को ओवरराइट करने जा रहा है ... यह अपरिभाषित व्यवहार है, इसलिए आप नाक राक्षसों के लिए प्रवण हैं।

नीचे की रेखा यह है कि जब आप स्मृति को लिखते हैं कि आपने स्पेस आवंटित नहीं किया है (या तो स्पष्ट रूप से मॉलोक या सरणी के साथ सरणी का उपयोग करके), तो आप आग से खेल रहे हैं। जल्दी या बाद में, आप स्मृति को ओवरराइट कर देंगे और खुद को दुःख के सभी प्रकार का कारण बनेंगे।

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

malloc(0) का मामला बस this question का एक विशेष मामला है।

+0

जब हम सूचक को कोई स्मृति निर्दिष्ट नहीं कर रहे हैं, ऐसे मामले में एक गैर मौजूद स्मृति में लिखने से सेगमेंटेशन गलती सही होनी चाहिए? मैं लिनक्स पर जीसीसी के साथ भी काम कर रहा हूं और सेगमेंटेशन गलती नहीं हो रही है। मैं malloc (0) के इस व्यवहार से उलझन में हूँ! – svKris

+0

@svKris मेरा सबसे अच्छा अनुमान यह है कि जब आप मॉलोक (0) चलाते हैं, तो आपको ढेर में कहीं पॉइंटर मिलता है। malloc किसी भी स्मृति को आरक्षित नहीं करता है, इसलिए आपके पास कोई गारंटी नहीं है कि आप ढेर में कहीं और डेटा ओवरराइट नहीं करेंगे, लेकिन यह (संभवतः) आप पर गलती नहीं करेगा। यदि आप एक प्रारंभिक पॉइंटर को लिखने का प्रयास करते हैं, तो आप किसके बारे में जानते हैं-कौन-मेमोरी पता है, इसलिए आप शायद गलती करेंगे। निष्पक्ष रूप से यह कैसे संभाला जाता है कार्यान्वयन निर्भर है। –

+0

@svkris ऊपर उद्धृत सी 99 मानक के अनुसार, malloc (0) शून्य वापस आ सकता है, या यह कुछ और वापस कर सकता है। एक नल पॉइंटर को लिखने से आपको सीजी गलती मिल जाएगी, इसलिए स्पष्ट रूप से यह नहीं है कि जीसीसी क्या करता है। –

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