मुझे realloc () के साथ दोहरी मुक्त त्रुटि क्यों मिल रही है?

मैंने सी में फ़ंक्शन को प्रतिस्थापित करने की कोशिश की है, जो char * पर काम करता है, जिसे malloc() का उपयोग करके आवंटित किया गया है। यह थोड़ा अलग है कि यह प्रारंभिक स्ट्रिंग में वर्णों की बजाय तारों को ढूंढ और प्रतिस्थापित करेगा।

यदि खोज और प्रतिस्थापन तार समान लंबाई हैं (या प्रतिस्थापन स्ट्रिंग खोज स्ट्रिंग से छोटा है), क्योंकि मेरे पास आवंटित पर्याप्त स्थान है, तो यह करना मुश्किल है। यदि मैं realloc() का उपयोग करने का प्रयास करता हूं, तो मुझे एक त्रुटि मिलती है जो मुझे बताती है कि मैं एक डबल फ्री कर रहा हूं - जो मुझे नहीं लगता कि मैं कैसे हूं, क्योंकि मैं केवल realloc ( )

शायद थोड़ा कोड मदद करेगा:

void strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while (find = strstr(find, search)) {

        if (delta > 0) {
            realloc(input, strlen(input) + delta);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) - (find - input));
        memmove(find, replace, replaceLen);
    }
}

प्रोग्राम तब तक काम करता है जब तक कि मैं एक उदाहरण में realloc() को आज़माता हूं, जहां प्रतिस्थापित स्ट्रिंग प्रारंभिक स्ट्रिंग से अधिक होगी। (यह अभी भी काम करता है, यह सिर्फ त्रुटियों के साथ-साथ परिणाम भी थूकता है)।

अगर यह मदद करता है, तो कॉलिंग कोड इस तरह दिखता है:

#include 
#include 
#include 

void strrep(char *input, char *search, char *replace);

int main(void) {
    char *input = malloc(81);

    while ((fgets(input, 81, stdin)) != NULL) {
        strrep(input, "Noel", "Christmas");
    }
}
0
जोड़ा संपादित
विचारों: 1

12 उत्तर

आप सीरियल इंटरफ़ेस के साथ वाईफ़ाई मॉड्यूल खरीद सकते हैं, लेकिन वे हैं थोड़ा सा सस्ता असल में आप उन्हें यूएआरटी के माध्यम से नियंत्रित करते हैं, और आप उन्हें पुरानी दिनों में डायल-अप मोडेम नियंत्रित करने के समान एटी कमांड भेजते हैं।

WiFi module

5
जोड़ा
यह एक अच्छा विचार है, और मुझे एकीकरण को और भी आसान बनाने के लिए इसके साथ ब्रेकआउट बोर्ड भी मिला। मेरा एकमात्र आरक्षण बिजली की आवश्यकताओं और आकार के साथ था। तुम्हारे सुझाव के लिए धन्यवाद! भविष्य में परियोजनाओं के लिए मुझे निश्चित रूप से याद होगा :-)
जोड़ा लेखक Mario Marinato, स्रोत

थोड़ा और विस्तार।

डेवर ने सुझाव दिया कि मैं भी सुझाव देने जा रहा था। रोइंग नेटवर्क भी बीटी मॉड्यूल का एक अच्छा सेट बनाता है।

विस्तार करने के लिए। ZigBee वाई-फाई से पूरी तरह से एक अलग प्रोटोकॉल है। ज़िगबी विकिरण शक्ति में बीटी के समान है, जो कि बड़ी मात्रा में सीमा से संबंधित है, लेकिन यह अलग है कि इसे कई नोड्स को नेटवर्क बनाने की अनुमति देने के लिए डिज़ाइन किया गया है, प्रत्येक नोड प्रभावी ढंग से नेटवर्क की सीमा को विस्तारित करता है। मुझे उम्मीद है कि यह साफ हो जाएगा कि वे समान हैं लेकिन संबंधित नहीं हैं।

3
जोड़ा
जानकारी के लिए धन्यवाद। मेरे पास कुछ प्रश्नों को साफ़ करने में मदद मिली :)
जोड़ा लेखक Mario Marinato, स्रोत

बस मेरे साथ अपने वर्तमान समाधान साझा करना चाहता था:

लिटिलबर्डइलेक्ट्रॉनिक्स में मार्कस और मेडलेन के साथ चैट करने के बाद, हम निम्नलिखित संभावित समाधान के साथ आए हैं:

1) लिलीपैड पर एक्सबी,

2) यूएसबी Arduino, ईथरनेट शील्ड और Xbee कॉम्बो WWW को संदेश स्थानांतरित करने के लिए।

यह केवल कई संभावित समाधानों में से एक है, लेकिन मेरे लिए यह लिलीपैड पर सीधे 802.11 का उपयोग करने के बजाय xbee का उपयोग करके लिलीपैड अंत पर कम शक्ति और आकार की आवश्यकताओं के लाभ प्रदान करता है।

इसके अलावा, मेरे पास पहले से ही एक अतिरिक्त Arduino और ईथरनेट ढाल अप्रयुक्त जा रहा था, और xbee के साथ खेलने के लिए एक बहाना चाहता था! ;-)

आपके निवेश - सहयोग के लिए धन्यवाद! यह समाधान तैयार करने में बहुत उपयोगी था।

3
जोड़ा
हमने दोनों को माना, लेकिन हमने पाया मॉड्यूल महंगा और विदेशी था। यह देखते हुए कि मेरे पास पहले से ही एक Arduino और एक ईथरनेट ढाल था, यह थोड़ा आसान हो गया :-) आपके सुझाव के लिए बहुत बहुत धन्यवाद!
जोड़ा लेखक Mario Marinato, स्रोत
मुझे लगता है कि मेरे द्वारा सुझाया गया समाधान सस्ता होगा। लेकिन हो सकता है कि आपका निर्माण अधिक ठोस, कॉम्पैक्ट और आसान हो। और आप पहले से ही हार्डवेयर हार्डवेयर।
जोड़ा लेखक Chris Bunch, स्रोत

क्या मैं अपने घर राउटर के साथ एक्सबीई मॉड्यूल और किसी भी तरह इंटरफ़ेस का उपयोग कर सकता हूं?

हां लेकिन आपको XBee मॉड्यूल को अपने राउटर से कनेक्ट करने की आवश्यकता है। यदि आपके राउटर में यूएसबी पोर्ट है तो आप अपने राउटर बोर्ड पर या यूएसबी द्वारा सीरियल एडाप्टर पर सीरियल पोर्ट खोजने का प्रयास कर सकते हैं। इसके अलावा आपके राउटर को लिनक्स (शायद ओपनडब्लूआरटी) के तहत काम करना चाहिए।

1
जोड़ा

एक सामान्य नियम के रूप में, आपको बफर प्रदान किए गए उपयोगकर्ता पर कभी नहीं निःशुल्क या पुनर्विक्रय करना चाहिए। आप नहीं जानते कि उपयोगकर्ता ने स्थान आवंटित किया है (आपके मॉड्यूल में, किसी अन्य डीएलएल में) ताकि आप किसी उपयोगकर्ता बफर पर आवंटन कार्यों का उपयोग न कर सकें।

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

फिर आप एकाधिक प्रतिस्थापन करने के लिए एक और फ़ंक्शन बना सकते हैं, लेकिन आपको परिणामी स्ट्रिंग के लिए पूरी जगह आवंटित करनी होगी और उपयोगकर्ता इनपुट स्ट्रिंग की प्रतिलिपि बनाना होगा। फिर आपको आवंटित स्ट्रिंग को हटाने का एक तरीका प्रदान करना होगा।

जिसके परिणामस्वरूप:

void  strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void  strrepmfree(char *input);
0
जोड़ा

मेरे त्वरित संकेत।

Instead of:
void strrep(char *input, char *search, char *replace)
try:
void strrep(char *&input, char *search, char *replace)

and than in the body:
input = realloc(input, strlen(input) + delta);

आम तौर पर मान / संदर्भ और realloc() विवरण के रूप में कार्य तर्कों को गुजरने के बारे में पढ़ें :)।

0
जोड़ा
नोटेशन <�कोड> शून्य स्ट्रैप (char * और इनपुट, char * search, char * प्रतिस्थापित) सी में मान्य नहीं है? हालांकि यह सी ++ में मान्य है। सवाल नहीं है, और AFAICT कभी नहीं था, सी ++ के साथ टैग किया गया। सबसे अच्छा, कोड शून्य strrep (char ** इनपुट, char * search, char * replace) होना चाहिए, हालांकि यह तर्क देना आसान है कि char * strrep (const char * input, कॉन्स char * खोज, कॉन्स char * प्रतिस्थापित करें) एक व्यावहारिक इंटरफ़ेस है (इनपुट स्ट्रिंग्स नहीं बदले गए हैं; संशोधित स्ट्रिंग आवंटित और लौटा दी गई है)।
जोड़ा लेखक Jonathan Leffler, स्रोत

नोट, एचटीएमएल से बचने के कोड से छुटकारा पाने के लिए अपना कोड संपादित करने का प्रयास करें।

खैर, हालांकि यह थोड़ी देर के बाद से मैंने सी / सी ++ का उपयोग किया है, फिर भी आपके मूल ब्लॉक के बाद मेमोरी में कमरा होने पर मेमोरी पॉइंटर वैल्यू का पुन: उपयोग होता है।

उदाहरण के लिए, इस पर विचार करें:

(Xxxxxxxxxx ..........)

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

हालांकि, यदि आप बाद में इसे 10 बाइट्स द्वारा विकसित करने का प्रयास करते हैं, और केवल 5 उपलब्ध हैं, तो इसे ब्लॉक में स्मृति को स्थानांतरित करने और अपने सूचक को अपडेट करने की आवश्यकता होगी।

हालांकि, आपके उदाहरण में आप फ़ंक्शन को चरित्र के लिए एक पॉइंटर पास कर रहे हैं, न कि आपके चर के लिए पॉइंटर, और इस प्रकार स्ट्रैप फ़ंक्शन आंतरिक रूप से उपयोग में चर समायोजित करने में सक्षम हो सकता है, यह स्ट्रैप फ़ंक्शन के लिए एक स्थानीय चर है और आपका कॉलिंग कोड मूल पॉइंटर चर वैल्यू के साथ छोड़ा जाएगा।

हालांकि, यह सूचक मूल्य मुक्त कर दिया गया है।

आपके मामले में, इनपुट अपराधी है।

हालांकि, मैं एक और सुझाव दूंगा। आपके मामले में ऐसा लगता है कि इनपुट चर वास्तव में इनपुट है, और यदि ऐसा है, तो इसे संशोधित नहीं किया जाना चाहिए।

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

0
जोड़ा

यह काम करता प्रतीत होता है;

char *strrep(char *string, const char *search, const char *replace) {
    char *p = strstr(string, search);

    if (p) {
        int occurrence = p - string;
        int stringlength = strlen(string);
        int searchlength = strlen(search);
        int replacelength = strlen(replace);

        if (replacelength > searchlength) {
            string = (char *) realloc(string, strlen(string) 
                + replacelength - searchlength + 1);
        }

        if (replacelength != searchlength) {
            memmove(string + occurrence + replacelength, 
                        string + occurrence + searchlength, 
                        stringlength - occurrence - searchlength + 1);
        }

        strncpy(string + occurrence, replace, replacelength);
    }

    return string;
}

श्वास, क्या चूसने के बिना कोड पोस्ट करने के लिए वैसे भी है?

0
जोड़ा
टिप्पणी जोड़ने से पहले टिप्पणी को उत्तर के रूप में लिखा गया था, क्योंकि यह पहली घटना को बदलता है। जो शायद उचित है, क्योंकि मैंने वास्तव में यह नहीं बताया था कि इसे सभी को बदलना होगा!
जोड़ा लेखक Matthew Schinckel, स्रोत

डेढ़ महीने पहले पार्टी के लिए देर से होने के लिए किसी और ने माफ़ी मांगी। ओह ठीक है, मैं सॉफ्टवेयर पुरातत्व करने में काफी समय बिताता हूं।

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

विश्लेषण करने से पहले, मैं उन लोगों से सहमत हूं जो कहते हैं कि आपका इंटरफ़ेस तारकीय से कम है; हालांकि, अगर आपने मेमोरी रिसाव / ट्रामप्लिंग मुद्दों के साथ निपटाया है और 'आवंटित स्मृति आवंटित' की आवश्यकता है, तो यह 'ठीक' हो सकता है।

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

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

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

तो, आपके बुलाए गए फ़ंक्शन का मेरा सुझाया गया संशोधन है:

char *strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while ((find = strstr(find, search)) != 0) {
        if (delta > 0) {
            input = realloc(input, strlen(input) + delta + 1);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) + 1 - (find - input));
        memmove(find, replace, replaceLen);
    }

    return(input);
}

यह कोड स्मृति आवंटन त्रुटियों का पता नहीं लगाता है - और संभवतः क्रैश (लेकिन यदि नहीं, स्मृति को लीक करता है) यदि realloc() विफल रहता है। स्मृति प्रबंधन मुद्दों की व्यापक चर्चा के लिए स्टीव Maguire के 'लेखन ठोस कोड' पुस्तक देखें।

0
जोड़ा
धन्यवाद, यह वास्तव में एक अच्छा विश्लेषण है कि मैं क्या गलत कर रहा था (और यह कि डबल-फ्री एक ऐसी चीज थी जो कई चीजों के गलत उत्पाद में था।) मुझे लगता है कि मेरे सिर में यह था कि realloc ( ) बस मेमोरी आवंटन बढ़ाया - जो मुझे कोई समझ नहीं आता, जब मैं इसके बारे में सोचता हूं!
जोड़ा लेखक Matthew Schinckel, स्रोत

realloc अजीब, जटिल है और केवल प्रति सेकंड कई बार स्मृति के साथ काम करते समय उपयोग किया जाना चाहिए। यानी - जहां यह वास्तव में आपके कोड को तेज़ी से बनाता है।

मैंने कोड देखा है

realloc(bytes, smallerSize);

बफर का आकार बदलने के लिए इस्तेमाल किया गया था और इसे छोटा बना दिया गया था। लगभग दस लाख बार काम किया, फिर किसी कारण से रीयलॉक ने फैसला किया कि भले ही आप बफर को छोटा कर रहे हों, यह आपको एक अच्छी नई प्रतिलिपि देगा। तो बुरी चीजें होने के बाद आप एक यादृच्छिक जगह 1/2 में दुर्घटनाग्रस्त हो जाते हैं।

हमेशा realloc के वापसी मूल्य का उपयोग करें।

0
जोड़ा

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

input = realloc(input, strlen(input) + delta);
0
जोड़ा
और यदि रीलॉक विफल हो जाता है, तो यह न्यूल लौटाता है, और मौजूदा बफर को अकेला छोड़ देता है। आपने अभी पॉइंटर खो दिया है ... :-(
जोड़ा लेखक Roger Lipscombe, स्रोत

सबसे पहले, खेद है कि मैं पार्टी के लिए देर हो चुकी हूँ। यह मेरा पहला स्टैक ओवरफ्लो उत्तर है। :)

जैसा कि इंगित किया गया है, जब realloc() कहा जाता है, तो आप सूचक को संभावित रूप से स्मृति में बदलने के लिए संभावित रूप से बदल सकते हैं। जब ऐसा होता है, तो तर्क "स्ट्रिंग" अमान्य हो जाता है। यहां तक ​​कि यदि आप इसे फिर से सौंप देते हैं, तो फ़ंक्शन समाप्त हो जाने पर परिवर्तन गुंजाइश से बाहर हो जाता है।

ओपी का जवाब देने के लिए, realloc() नई पुनरावृत्ति स्मृति में एक सूचक देता है। वापसी मूल्य कहीं भी संग्रहीत करने की जरूरत है। आम तौर पर, आप यह करेंगे:

data *foo = malloc(SIZE * sizeof(data));
data *bar = realloc(foo, NEWSIZE * sizeof(data));

/* Test bar for safety before blowing away foo */
if (bar != NULL)
{
   foo = bar;
   bar = NULL;
}
else
{
   fprintf(stderr, "Crap. Memory error.\n");
   free(foo);
   exit(-1);
}

जैसा कि TyBoer बताता है, आप लोग इस फ़ंक्शन में इनपुट के रूप में पास होने वाले पॉइंटर के मान को नहीं बदल सकते हैं। आप जो कुछ भी चाहते हैं उसे असाइन कर सकते हैं, लेकिन फ़ंक्शन के अंत में परिवर्तन दायरे से बाहर हो जाएगा। निम्न ब्लॉक में, फ़ंक्शन पूरा होने के बाद "इनपुट" अमान्य पॉइंटर हो सकता है या नहीं भी हो सकता है:

void foobar(char *input, int newlength)
{
   /* Here, I ignore my own advice to save space. Check your return values! */
   input = realloc(input, newlength * sizeof(char));
}

मार्क नए पॉइंटर को फ़ंक्शन के आउटपुट के रूप में लौटकर इस पर काम करने की कोशिश करता है। यदि आप ऐसा करते हैं, तो कॉलर कॉलर पर है जो इनपुट के लिए उपयोग किए गए पॉइंटर का कभी भी उपयोग नहीं करता है। यदि यह रिटर्न वैल्यू से मेल खाता है, तो आपके पास एक ही स्थान पर दो पॉइंटर्स हैं और केवल उनमें से एक पर मुफ्त() कॉल करने की आवश्यकता है। यदि वे मेल नहीं खाते हैं, तो इनपुट पॉइंटर अब स्मृति को इंगित करता है जो प्रक्रिया के स्वामित्व में हो सकता है या नहीं। इसे अस्वीकार करने से विभाजन विभाजन हो सकता है।

आप इनपुट के लिए एक डबल पॉइंटर का उपयोग कर सकते हैं, इस तरह:

void foobar(char **input, int newlength)
{
   *input = realloc(*input, newlength * sizeof(char));
}

यदि कॉलर के पास कहीं भी इनपुट पॉइंटर का डुप्लिकेट है, तो वह डुप्लिकेट अभी भी अमान्य हो सकता है।

मुझे लगता है कि फ़ंक्शन कॉलर के इनपुट को संशोधित करने का प्रयास करते समय realloc() का उपयोग करने से बचने के लिए सबसे साफ समाधान है। बस malloc() एक नया बफर, इसे वापस करें, और कॉलर को यह तय करने दें कि पुराने पाठ को मुक्त करना है या नहीं। कॉलर को मूल स्ट्रिंग रखने के लिए इसका अतिरिक्त लाभ है!

0
जोड़ा