2011-11-12 19 views
10

मुक्त हो जाता है मैं सी में नया हूँ, सी कि मैं थोड़े उलझनजब सी में सूचक मुक्त करने के लिए और कैसे पता करने के लिए अगर यह

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

typedef struct 
{ 
    int a; 
} struct1_t; 

int main() 
{ 
    funct1(); //init pointer 
    return 1; 
} 


int funct2(struct1_t *ptr2struct) 
{ 
    printf("print a is %d\n",ptr2struct->a); 
    //free(ptr2struct); 
    printf("value of ptr in funct2 is %p\n", ptr2struct); 
    return 1; //success 
} 


int funct1(){ 

    struct1_t *ptr2struct = NULL; 
    ptr2struct = malloc(sizeof(*ptr2struct)); 
    ptr2struct->a = 5; 
    printf("value of ptr before used is %p", ptr2struct); 
    if (funct2(ptr2struct) == 0) { 
     goto error; 
    } 
    free(ptr2struct); 

    printf("value of ptr in funct1 after freed is is %p\n", ptr2struct); 
    return 1; 

error: 
    if(ptr2struct) free(ptr2struct); 
    return 0; 
} 

मैं funct 1 है funct कॉल में स्मृति आवंटन के बारे में पता लगाने की कोशिश 2, और funct1 में आवंटित सूचक का उपयोग करने के बाद, मैं सूचक को मुक्त करने का प्रयास करता हूं। और मैं एक मामला बना देता हूं जहां funct2 में वापसी मान 1 नहीं है, तो पॉइंटर को मुक्त करने के लिए फिर से प्रयास करें।

मेरा प्रश्न नीचे

जो अभ्यास के लिए बेहतर है, मैं स्मृति funct2 में मुक्त करता है, तो चाहिए (के बाद मैं इसे पारित) या funct1 में (के बाद मैं funct1 की वापसी मान रही समाप्त करने के बाद) है दूसरी बात यह है कि क्या यह एक गोटो त्रुटि, और त्रुटि बनाने के लिए सही है:

if(ptr2struct) free(ptr2struct); 

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

उत्तर

10

1) क्या मुझे इसे कॉलिंग फ़ंक्शन या बुलाए गए फ़ंक्शन में मुक्त करना चाहिए?

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

2) क्या यह "गोटो त्रुटि" करना सही है?

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

//in the middle of the function, whenever you would have a return statement 
// instead do 
return_value = something; 
goto DONE; 

//... 

DONE: 
    //resorce management code all in one spot 
    free(stuff); 
    return return_value; 

सी ++, दूसरे हाथ पर, एक साफ रास्ता संसाधन प्रबंधन के इस प्रकार का है। चूंकि विनाशकों को फ़ंक्शन से बाहर निकलने से पहले निश्चित रूप से बुलाया जाता है, इसलिए उन्हें संसाधन प्रबंधन के इस राजा को अच्छी तरह से पैकेज करने के लिए उपयोग किया जा सकता है। वे इस तकनीक को RAII

अन्य भाषाओं को इसके साथ सौदा करने का एक और तरीका अंततः ब्लॉक है।

3) क्या मैं देख सकता हूं कि कोई सूचक पहले से ही मुक्त हो चुका है या नहीं?

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

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

+6

को छोड़कर एक ही चीज़ है, यदि आप एक ही समारोह में आवंटित और मुक्त कर सकते हैं, शायद आपको इसे ढेर पर रखना चाहिए। –

+0

@missingno: इसके लिए, यह सही है: "अगर (ptr2struct) मुक्त (ptr2struct);" या मुझे सिर्फ "मुक्त (ptrstruct) लिखना चाहिए। क्योंकि मुझे लगता है कि ptr2struct एक सूचक है, इसलिए एक बूल वैल्यू नहीं है, क्या मैं रिटर्न वैल्यू सही नहीं होने पर गेटो के अंदर इस नोटेशन का उपयोग कर सकता हूं? धन्यवाद – xambo

+1

@MK: कुछ चीजें (सी 99 से पहले परिवर्तनीय-लंबाई सरणी की तरह) अभी भी मॉलोक-एड होने की आवश्यकता है। फिर भी, एक दूसरे के पास आवंटन और विलोपन रखने की कोशिश कर रहे हैं (अवधारणात्मक रूप से - इसे सख्ती से एक ही कार्य में होने की आवश्यकता नहीं है) आमतौर पर बेहतर होता है। – hugomg

11

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

+0

मुझे पता है कि यह एक सी प्रश्न है लेकिन इसे 0 (शून्य) पर भी सेट करना अच्छा है - 0 और न्यूल कुछ भाषा sematics –

1

My question is below

which practice is better, if I should free the memory in funct2 (after I pass it) or in funct1 (after I finish getting the return value of funct1)

यह एक "स्वामित्व" प्रश्न है। आवंटित स्मृति का मालिक कौन है। आमतौर पर, यह आपके कार्यक्रम के डिजाइन के आधार पर तय किया जाना है। उदाहरण के लिए, func1() का एकमात्र उद्देश्य केवल स्मृति आवंटित किया जा सकता है। यही है, आपके कार्यान्वयन में, func1() स्मृति आवंटन के लिए फ़ंक्शन है और फिर "कॉलिंग" फ़ंक्शन स्मृति का उपयोग करता है। उस स्थिति में, स्मृति को मुक्त करने के स्वामित्व func1 के कॉलर के साथ है और func1() के साथ नहीं है।

The second thing is whether this is correct to make a goto error, and error: The use of "goto" is generally frowned about. It causes mess in the code that could just be easily avoided. However, I say "generally". There are cases where goto can be quiet handy and useful. For example, in big systems, configuration of the system is a big step. Now, imagine you call a single Config() function for the system which allocates memory for its different data structures at different points in the function like

config() 
    { 
     ...some config code... 
     if (a specific feature is enabled) 
     { 
     f1 = allocateMemory(); 
     level = 1; 
     } 
     ....some more code.... 
     if (another feature is enabled) 
     { 
     f2 = allocateMemory(); 
     level = 2; 
     } 

     ....some more codee.... 
     if (another feature is enabled) 
     { 
     f3 = allocateMemor(); 
     level =3; 
     } 

     /*some error happens */ 
     goto level_3; 


    level_3: 
     free(f3); 
    level_2: 
     free(f2); 
    level_1: 
     free(f1); 
} 

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

हालांकि, आपके उदाहरण में कहने के लिए पर्याप्त है कि आसानी से टालने योग्य है और इससे बचा जाना चाहिए।

My third question is , how do I check if the allocated value is already freed or not? because after getting the return value, I free the pointer, but if I print it, it shows the same location with the allocated one (so not a null pointer).

आसान। मुक्त स्मृति को न्यूल के रूप में सेट करें। अन्य लाभ, एमके द्वारा वर्णित एक के अलावा, यह है कि मुक्त पॉइंटर को मुक्त करने से एनओपी हो जाएगा यानी कोई ऑपरेशन नहीं किया जाता है। इससे आपको किसी भी डबल डिलीट समस्याओं से बचने में मदद मिलेगी।

+0

तो अगर मैं स्तर पर लिखने के लिए स्तर_3: अगर (एफ 3) मुक्त (एफ 3)। तो मान लीजिए कि अगर एफ 3 का मूल्य है, तो इसे मुक्त करें। या? – xambo

+0

xambo: हाँ यह अनावश्यक हालांकि सही है। उदाहरण में, विचार यह है कि यदि आप स्तर 3 पर हैं, तो f3 सफलतापूर्वक आवंटित किया गया होगा। –

+0

यदि आपको स्तर स्तर मिल गया है, तो आप उन तीनों को मुक्त कर देंगे। यदि आपको स्तर 2 है, तो आप केवल एफ 2 और एफ 1, आदि स्विच मामलों की तरह काम करता है जिनमें ब्रेक नहीं होते हैं जहां निष्पादन अगले मामले में आता है। – gone

1

जो मैं साझा करने जा रहा हूं वह सी में अपना खुद का विकास प्रथा है। वे स्वयं को व्यवस्थित करने का एकमात्र तरीका नहीं हैं। मैं सिर्फ तरीके से तरीके से रूपरेखा नहीं कर रहा हूं।

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

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

  • यदि मेरे पास एक ऐसी संरचना है जिसका उपयोग पूरे सॉफ़्टवेयर में किया जाता है, तो मैं लिखता/नष्ट करता हूं; इसके लिए init/done type functions:

    struct foo * init_foo(); 
    void done_foo(struct foo *); 
    

    और इन कार्यों में संरचना आवंटित और आवंटित करें।

  • यदि मैं प्रोग्राम पर सीधे संरचना तत्वों का उपयोग करता हूं तो इसे टाइप नहीं किया जाता है। मैं प्रत्येक घोषणा में संरचना कीवर्ड का उपयोग करने का दर्द लेता हूं ताकि मुझे पता चले कि यह एक संरचना है। यह पर्याप्त है जहां दर्द की सीमा इतनी ज्यादा नहीं है कि मैं इससे नाराज हो जाऊंगा। :-)

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

foo.h:

struct foo; 
typedef struct foo foo_t; 

void set_e1(foo_t f, int e1); 
int get_ei(foo_t f); 

int set_buf(foo_t f, const char *buf); 
char * get_buf_byref(foo_t f) 
char * get_buf_byval(foo_t f, char *dest, size_t *dlen); 

foo.c:

#include <foo.h> 

struct foo { 
    int e1; 
    char *buf; 
    ... 
}; 

void set_e1(foo_t f, int e1) { 
     f->e1 = e1; 
} 

int get_ei(foo_t f) { return f->e1; } 

void set_buf(foo_t f, const char *buf) { 
    if (f->buf) free (f->buf); 
    f->buf = strdup(buf); 
} 

char *get_buf_byref(foo_t f) { return f->buf; } 
char *get_buf_byval(foo_t f, char **dest, size_t *dlen) { 
    *dlen = snprintf(*dest, (*dlen) - 1, "%s", f->buf); /* copy at most dlen-1 bytes */ 
    return *dest; 
} 
  • संबंधित संरचनाओं बहुत जटिल रहे हैं, तो आप भी सही एक आधार में समारोह संकेत लागू करने के लिए चाहते हो सकता है संरचना और फिर उस संरचना के विशेष विस्तार में वास्तविक मैनिपुलेटर प्रदान करते हैं।

आप ऊपर उल्लिखित दृष्टिकोण और ऑब्जेक्ट उन्मुख प्रोग्रामिंग के बीच एक मजबूत समानता देखेंगे। इसका मतलब यह है कि ...

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

उम्मीद है कि इससे मदद मिलती है।

+0

मैं 'struct' – hugomg

+0

:-) टाइप करने से बचने के लिए" structs के लिए अपरकेस "सम्मेलन में चिपकना पसंद करता हूं जो इसे करने का एक बिल्कुल वैध तरीका है। संगति जाने का रास्ता है। मैं टाइटलकेसिंग दृष्टिकोण से बचता हूं क्योंकि इसका आमतौर पर सी ++ या जावा में उपयोग किया जाता है; और अक्सर मैं सी कोड लिखना समाप्त करता हूं जिसका उपयोग उन भाषाओं में से किसी एक में किया जाता है, इसलिए मैं टाइप-अप के लिए foo_t सम्मेलन का उपयोग करता हूं या गैर-प्रकार के डीफ़ के लिए स्ट्रक्चर फू का उपयोग करता हूं। फिर यह व्यक्तिगत वरीयता है और आंखों पर आपका रास्ता निश्चित रूप से आसान है :-)। –

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