2011-02-15 10 views
10

मैं कुछ हद तक उलझन में हूं जब आप सी में एक चार सूचक पर स्ट्रोक को कॉल करते हैं। मुझे पता है कि यह स्ट्रिंग की सामग्री को संशोधित करता है, इसलिए यदि मैं 'लाइन' नामक चर पर स्ट्रोक को कॉल करता हूं, तो इसकी सामग्री बदल जाएगी। मान लें मैं bellow दृष्टिकोण का पालन करें:सी में स्ट्रोकोक का उपयोग कैसे करें ताकि कोई स्मृति रिसाव न हो?

void function myFunc(char* line) { 

    // get a pointer to the original memory block 
    char* garbageLine = line; 

    // Do some work 
    // Call strtok on 'line' multiple times until it returns NULL 
    // Do more work 

    free(garbageLine); 
} 

इसके अलावा मान से पहले यह myFunc को पारित कर दिया है कि 'लाइन' malloced है। क्या मुझे स्ट्रोक का उपयोग करने के बाद मूल स्ट्रिंग को मुक्त करना है या क्या यह हमारे लिए काम करता है? साथ ही, क्या होता है यदि 'लाइन' को मॉलोक नहीं किया गया है और मैं ऊपर दिए गए फ़ंक्शन का उपयोग करने का प्रयास करता हूं? क्या इसके बजाय निम्नलिखित करना सुरक्षित है? (मान लें प्रोग्रामर मुक्त फोन नहीं होगा वह जानता है कि अगर लाइन malloced नहीं है)

प्रार्थना किए

char* garbageLine = line; 
myFunc(line); 
free(garbageLine); 

समारोह परिभाषा

void function myFunc(char* line) { 
    // Do some work 
    // Call strtok on 'line' multiple times until it returns NULL 
    // Do more work 
} 

उत्तर

8

strtok() कुछ भी मुक्त नहीं होगा, क्योंकि इसमें कोई जानकारी नहीं है कि स्ट्रिंग कहाँ संग्रहित है। यह ढेर या ढेर पर हो सकता है, यह नहीं जानता या परवाह नहीं है! :)

क्या इसके बजाय निम्नलिखित करना सुरक्षित है?

आपका दूसरा उदाहरण बहुत बेहतर है, क्योंकि यह myFunc() को सरल बनाता है, और इसे अधिक स्थितियों में उपयोगी बनाता है क्योंकि फ़ंक्शन को आवंटित करने की आवश्यकता नहीं होती है। कॉल को मुफ्त में() से MyFunc() से हटाकर आप स्टैक या ढेर से तारों को पार्स करने के लिए फ़ंक्शन का उपयोग करने में सक्षम हैं। कॉलर स्मृति आवंटित करता है, कॉलर स्मृति को मुक्त करता है!

अतिरिक्त पठन: strtok()

+0

+1 :-) –

+0

ध्यान दें कि दूसरा दृष्टिकोण 'myFunc (line) में सरलीकृत किया जा सकता है; मुफ्त (रेखा); '- अस्थायी अनावश्यक है क्योंकि सूचक 'लाइन' को' myFunc()' मान द्वारा पारित किया जाता है। – caf

+0

@caf आप निश्चित रूप से मान रहे हैं कि ओपी वास्तव में लाइन को malloced है, लेकिन यह कोड से स्पष्ट नहीं है। स्मृति आवंटन और विलोपन के बारे में स्पष्ट भ्रम को देखते हुए, धारणा की आवश्यकता नहीं है। –

0

इस के साथ क्या संबंध है क्या strtok()? यदि आप स्मृति आवंटित करते हैं, तो आपको इसे मुक्त करने की आवश्यकता है। जहां आपका आवेदन आवंटित करने और स्मृति मुक्त करने का निर्णय लेता है, वह आपके ऊपर है। लेकिन अगर आप स्मृति को strtok() पर पास करते हैं, तो इससे कोई फर्क नहीं पड़ता कि स्मृति या आवंटित होने पर कोई फर्क नहीं पड़ता।

+0

क्या मैं उन दोनों दृष्टिकोणों में स्मृति को निष्क्रिय करता हूं? मैं सोच रहा हूं कि अगर स्ट्रोक पूरी तरह स्मृति को हटा देता है। ध्यान रखें कि मैं भाषा में एक विशेषज्ञ नहीं हूं। – user246392

+0

@ user246392: जैसा कि मैंने अपने जवाब में कहा था, 'strtok()' को कॉल करने से आवंटित स्मृति पर कोई प्रभाव नहीं पड़ता है। यह किसी भी स्मृति आवंटित या मुक्त नहीं करता है। यह स्मृति आवंटित या मुक्त करने के सवाल से प्रासंगिक नहीं है। अक्सर, यह उसी आवृत्ति से मुक्त स्मृति को समझ में आता है जो इसे आवंटित करता है, लेकिन यदि यह आपके ऐप में फिट नहीं होता है, तो वास्तव में यह महत्वपूर्ण है कि यह मुक्त हो जाता है। –

+0

@ user246392 यह निर्धारित करना संभव नहीं है कि आप स्मृति को सही तरीके से हटा रहे हैं क्योंकि हमारे पास यह जानने का कोई तरीका नहीं है कि आपने * आवंटित * ​​कैसे किया है। मैं कह सकता हूं कि आप लगभग निश्चित रूप से गलत तरीके से कर रहे हैं। 'कॉलर फ्री मेमोरी' की सिफारिश करने के लिए –

-1

जब तक आप केवल "char *" प्रकार का उपयोग करते हैं, तो बफर ओवरफ्लो के कारण किसी भी स्ट्रिंग मैनिपुलेशन को सुरक्षित रूप से 100% करना असंभव होगा।

जहां तक ​​स्मृति रिसाव का संबंध है; यदि आप इसे आवंटित करते हैं, तो सबसे अच्छा अभ्यास उसी ब्लॉक (यदि संभव हो) में इसे हटाना है। इसका अर्थ यह है कि यदि आप स्ट्रोकोक कार्यान्वयन प्रदान करते हैं, तो इसे आंतरिक रूप से आवंटित किसी भी स्मृति को हटा देना चाहिए, लेकिन विधि में पारित किसी भी स्मृति को हटा नहीं देना चाहिए।

कारण कई गुना हैं, लेकिन मूल रूप से इस बात की कोई गारंटी नहीं है कि आपकी विधि का उपयोग करने वाले किसी अन्य व्यक्ति के पास इसके स्रोत कोड तक पहुंच होगी, इसलिए थोड़ा रास्ता है कि वे उचित रूप से आवंटित स्मृति को देखने के लिए तैयार होंगे (कोड के अपने हिस्से में सेगमेंटेशन गलती का कारण बनता है)।

"सुरक्षित" गैर-बफर ओवरफ़्लो स्ट्रिंग मैनिपुलेशन करने के लिए, आपको मैक्सीम गिनती मान भी होना चाहिए। उदाहरण के लिए, strncpy (...) "वर्णों की अधिकतम संख्या" पैरामीटर लेता है। यह कुछ प्रकार के हमलों को रोकता है जहां एक स्ट्रिंग की स्मृति आवंटन की स्मृति "डाउनस्ट्रीम" को डेटा द्वारा भर दिया जा सकता है जिसे बाद में कार्यक्रम के किसी अन्य भाग द्वारा कोड के रूप में व्याख्या किया जाता है।

इसका मतलब है कि आपके myFunc(char* line) को हस्ताक्षर myfunc(char* line, int max_chars) होना चाहिए और आपके बाद के सभी कार्यों को max_Chars + 1 मेमोरी की मात्रा की गारंटी दी जानी चाहिए। प्लस वन टर्मिनिंग नल को पकड़ना है, जो मौजूद नहीं हो सकता है। आंतरिक रूप से, आपको यह सुनिश्चित करने की ज़रूरत है कि स्ट्रैपी जैसे सभी ऑपरेशंस केवल पहले अधिकतम_चर्स पर चलते हैं (strncpy यह करता है)।

इसका मतलब है कि आप अंततः बफर ओवरफ्लो सुरक्षा के लिए एक स्ट्रिंग मैनिपुलेटर के "एन" (वर्णों की संख्या) संस्करण का पक्ष लेंगे। युगल कि एक मजबूत "ब्लॉक में आवंटित ब्लॉक" अभ्यास के साथ और आप 90% अधिकांश स्ट्रिंग-संबंधित प्रोग्रामिंग त्रुटियों से बचेंगे।

कभी-कभी आप बाद में (शायद मानचित्र में) आवंटित स्ट्रिंग को स्टोर करना चाहते हैं। उन मामलों के मामलों के साथ, आपको कार्यक्रम छोड़ने से पहले मानचित्र को साफ़ करने की देखभाल करने की आवश्यकता है, या कम से कम कुछ अन्य उपाय करें ताकि यह सुनिश्चित किया जा सके कि नक्शा उचित से अधिक अप्रयुक्त स्मृति को नहीं रखता है।

3

अपने प्रश्न में टिप्पणी में, आप कहते हैं कि तुम "जब तक यह NULL भेजता है 'लाइन' पर कई बार strtok कॉल करें"। ऐसा लगता है जैसे आप स्ट्रैटोक का गलत इस्तेमाल कर रहे हैं। पहली बार जब आप इसे कॉल करते हैं, तो आपको इसे तर्क के रूप में 'लाइन' के साथ कॉल करना चाहिए; बाद की कॉल पर, आपको इसे पास करना चाहिए। एक उदाहरण के रूप समझें:

void function myFunc(char* line) { 
    char *segment; // This will point at each delimited substring in turn. 

    segment = strtok(line, " "); 

    // Do something with segment. 

    segment = strtok(NULL, " "); 

    // Do something with the new segment. 

    free(line); 
} 

रूप DrTwox कहा, हालांकि, अपने दूसरे उदाहरण के लिए बेहतर है - 'लाइन' उसी संदर्भ है कि यह (या नहीं) malloced द्वारा मुक्त किया जाना चाहिए, कॉल मुक्त करने के लिए इतना () इस समारोह में नहीं है। और आप इसे पाशन से बेहतर कर रहे हैं - की तरह कुछ:

void function myFunc(char* line) { 
    char *segment; 

    segment = strtok(line, " "); 

    while (segment != NULL) { 
    // Do something with segment. 

    segment = strtok(NULL, " "); 
    } 
} 

प्रार्थना किए इस तरह है:

char *line = malloc(20*sizeof(char)); 

// Check that malloc succeeded here. 
// Put some data into 'line'. 

myFunc(line); 

free(line); 

// No 'garbageLine' required. 

तरीका है कि काम करता है strtok व्याख्या करने के लिए एक छोटे से जटिल है, लेकिन आप महत्वपूर्ण मिल गया है भागों - यह किसी भी स्मृति आवंटित या मुक्त नहीं करता है। इसके बजाए, यह आपके द्वारा पारित स्ट्रिंग को संशोधित करके काम करता है।

+0

+1 का उल्लेख करने के लिए +1 'स्ट्रेटोक (लाइन, "")' तब तक काम नहीं करता जब तक कि सभी स्ट्रेटोक 'को' नॉट 'को किसी तर्क के रूप में प्राप्त न हो: 'स्ट्रोक (न्यूल," ");' –

1

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

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