C मेमोरी प्रबंधन


90

मैंने हमेशा सुना है कि सी में आपको वास्तव में देखना है कि आप मेमोरी कैसे प्रबंधित करते हैं। और मैं अभी भी सी सीखना शुरू कर रहा हूं, लेकिन इस प्रकार, मुझे अब तक किसी भी स्मृति से संबंधित गतिविधियों का प्रबंधन नहीं करना पड़ा है। मैंने हमेशा चर जारी करने और हर तरह की बदसूरत चीजों को करने की कल्पना की है। लेकिन यह मामला प्रतीत नहीं होता है।

क्या कोई मुझे (कोड उदाहरणों के साथ) एक उदाहरण दिखा सकता है जब आपको कुछ "मेमोरी मैनेजमेंट" करना होगा?


जवाबों:


230

ऐसी दो जगहें हैं जहाँ चर को स्मृति में रखा जा सकता है। जब आप इस तरह एक चर बनाते हैं:

int  a;
char c;
char d[16];

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

कई शुरुआती उदाहरण केवल स्टैक चर का उपयोग करेंगे।

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

यदि आप संकलन समय पर नहीं जानते हैं कि आपका सरणी कितना बड़ा है, या यदि आपको बड़े सरणी या संरचना की आवश्यकता है, तो आपको "प्लान बी" की आवश्यकता होगी।

प्लान बी को " हीप " कहा जाता है । आप आमतौर पर वैरिएबल बना सकते हैं जितना बड़ा ऑपरेटिंग सिस्टम आपको देगा, लेकिन आपको इसे स्वयं करना होगा। इससे पहले की पोस्टिंग ने आपको एक ऐसा तरीका दिखाया, जिससे आप इसे कर सकते हैं, हालाँकि अन्य तरीके भी हैं:

int size;
// ...
// Set size to some value, based on information available at run-time. Then:
// ...
char *p = (char *)malloc(size);

(ध्यान दें कि ढेर में चर सीधे जोड़ नहीं हैं, लेकिन संकेत के माध्यम से)

एक बार जब आप एक ढेर चर बनाते हैं, तो समस्या यह है कि संकलक यह नहीं बता सकता है कि आप इसके साथ कब कर रहे हैं, इसलिए आप स्वत: जारी करना खो देते हैं। यही वह जगह है जहाँ "मैनुअल रिलीज़" आप में आने का जिक्र कर रहे थे। आपका कोड अब यह तय करने के लिए ज़िम्मेदार है कि चर की अब और ज़रूरत नहीं है, और इसे रिलीज़ करें ताकि मेमोरी को अन्य उद्देश्यों के लिए लिया जा सके। उपरोक्त मामले के लिए:

free(p);

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

C और C ++ में, आप अपने हीप वैरिएबल को साफ करने के लिए जिम्मेदार हैं, जैसा कि ऊपर दिखाया गया है। हालाँकि, ऐसी भाषाएँ और वातावरण हैं जैसे जावा और .NET भाषाएँ जैसे C # जो एक अलग दृष्टिकोण का उपयोग करते हैं, जहाँ ढेर अपने आप साफ हो जाता है। "कचरा संग्रह" नामक यह दूसरी विधि, डेवलपर पर बहुत आसान है, लेकिन आप ओवरहेड और प्रदर्शन में जुर्माना का भुगतान करते हैं। यह एक संतुलन है।

(मैंने एक सरल विवरण देने के लिए कई विवरणों पर प्रकाश डाला है, लेकिन उम्मीद है कि अधिक स्तरीय उत्तर)


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

1
शायद आप वैश्विक चर की स्मृति स्थान के बारे में एक या दो वाक्य जोड़ सकते हैं
माइकल काफर

C में कभी नहीं लौटा malloc(), इसके कारण UB, (char *)malloc(size);देखें stackoverflow.com/questions/605845/…
EsmaeelE

17

यहाँ एक उदाहरण है। मान लें कि आपके पास एक स्ट्रिंग है () फ़ंक्शन जो एक स्ट्रिंग को डुप्लिकेट करता है:

char *strdup(char *src)
{
    char * dest;
    dest = malloc(strlen(src) + 1);
    if (dest == NULL)
        abort();
    strcpy(dest, src);
    return dest;
}

और आप इसे इस तरह कहते हैं:

main()
{
    char *s;
    s = strdup("hello");
    printf("%s\n", s);
    s = strdup("world");
    printf("%s\n", s);
}

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

यह स्मृति की इस छोटी राशि के लिए कोई बड़ी बात नहीं है, लेकिन इस मामले पर विचार करें:

for (i = 0; i < 1000000000; ++i)  /* billion times */
    s = strdup("hello world");    /* 11 bytes */

आपने अब 11 गिग मेमोरी (संभवतः अधिक, आपके मेमोरी मैनेजर पर निर्भर करता है) का उपयोग किया है और यदि आपने क्रैश नहीं किया है तो संभवतः आपकी प्रक्रिया बहुत धीमी गति से चल रही है।

ठीक करने के लिए, आपको मॉलॉक के साथ प्राप्त होने वाली हर चीज के लिए मुफ्त () कॉल करने की आवश्यकता है (इसे उपयोग करने के बाद):

s = strdup("hello");
free(s);  /* now not leaking memory! */
s = strdup("world");
...

आशा है कि यह उदाहरण मदद करता है!


मुझे यह उत्तर बेहतर लगा। लेकिन मुझे थोड़ा साइड सवाल मिला। मैं पुस्तकालयों के साथ इस तरह से हल होने की उम्मीद करूंगा, क्या ऐसा कोई पुस्तकालय नहीं है जो बुनियादी डेटाटाइप्स की बारीकी से नकल करेगा और मेमोरी फ्रीजिंग सुविधाओं को जोड़ देगा ताकि जब चर का उपयोग हो जाए तो वे स्वचालित रूप से मुक्त हो जाएं?
लोरेंजो

कोई भी ऐसा नहीं है जो मानक का हिस्सा है। यदि आप C ++ में जाते हैं तो आपको तार और कंटेनर मिलते हैं जो स्वचालित मेमोरी प्रबंधन करते हैं।
मार्क हैरिसन

मैं देख रहा हूँ, इसलिए कुछ 3 पार्टी लिबास हैं? क्या आप कृपया उनका नाम बता सकते हैं?
लोरेंजो

9

आपको स्टैक के बजाय ढेर पर मेमोरी का उपयोग करने के लिए "मेमोरी मैनेजमेंट" करना होगा। यदि आप नहीं जानते कि रनटाइम तक एक सरणी बनाने के लिए कितना बड़ा है, तो आपको ढेर का उपयोग करना होगा। उदाहरण के लिए, आप किसी स्ट्रिंग में कुछ संग्रहीत करना चाहते हैं, लेकिन यह नहीं जानते कि कार्यक्रम चलने तक इसकी सामग्री कितनी बड़ी होगी। उस मामले में आप कुछ इस तरह लिखेंगे:

 char *string = malloc(stringlength); // stringlength is the number of bytes to allocate

 // Do something with the string...

 free(string); // Free the allocated memory

5

मुझे लगता है कि सी में सूचक की भूमिका पर विचार करने के लिए सवाल का जवाब देने का सबसे संक्षिप्त तरीका है। सूचक एक हल्का अभी तक शक्तिशाली तंत्र है जो आपको पैर में खुद को गोली मारने की अपार क्षमता की कीमत पर अपार स्वतंत्रता देता है।

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

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

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

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


4

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

एक उदाहरण:

int main() {
    char* myString = (char*)malloc(5*sizeof(char));
    myString = "abcd";
}

इस बिंदु पर आपने myString के लिए 5 बाइट आवंटित किए हैं और इसे "abcd \ 0" के साथ भर दिया है (एक छोर में समाप्त होता है - \ 0)। यदि आपका स्ट्रिंग आवंटन था

myString = "abcde";

आपके द्वारा अपने कार्यक्रम के लिए आवंटित की गई 5 बाइट्स में आपको "abcde" असाइन किया जाएगा, और अनुगामी अशक्त चरित्र को इसके अंत में रखा जाएगा - स्मृति का एक हिस्सा जो आपके उपयोग के लिए आवंटित नहीं किया गया है और हो सकता है मुफ्त, लेकिन समान रूप से किसी अन्य अनुप्रयोग द्वारा उपयोग किया जा सकता है - यह स्मृति प्रबंधन का महत्वपूर्ण हिस्सा है, जहां एक गलती अप्रत्याशित (और कभी-कभी अप्राप्य) परिणाम होंगे।


यहां आप 5 बाइट आवंटित करते हैं। पॉइंटर असाइन करके इसे ढीला करें। इस सूचक को मुक्त करने का कोई भी प्रयास अपरिभाषित व्यवहार की ओर ले जाता है। नोट C- स्ट्रिंग्स ओवरलोड नहीं है = ऑपरेटर कोई प्रतिलिपि नहीं है।
मार्टिन यॉर्क

हालाँकि, यह वास्तव में उस मॉलोक पर निर्भर करता है जिसका आप उपयोग कर रहे हैं। कई मॉलोक संचालक 8 बाइट्स से संरेखित करते हैं। इसलिए यदि यह मॉलोक एक हेडर / फुटर प्रणाली का उपयोग कर रहा है, तो मॉलोक 5 + 4 * 2 (हेडर और फुटर दोनों के लिए 4 बाइट्स) आरक्षित करेगा। यह 13 बाइट्स होगा, और मॉलोक आपको संरेखण के लिए अतिरिक्त 3 बाइट्स देगा। मैं यह नहीं कह रहा हूं कि इसका उपयोग करना एक अच्छा विचार है, क्योंकि यह केवल उन्हीं सिस्टमों का होगा जिनके मॉलोक इस तरह से काम करते हैं, लेकिन यह जानना कम से कम महत्वपूर्ण है कि कुछ गलत काम क्यों हो सकता है।
कोदई

लोकी: मैंने strcpy()इसके बजाय उपयोग करने का उत्तर संपादित किया है =; मुझे लगता है कि क्रिस बीसी का इरादा था।
इच्रस्टोफरसन

मेरा मानना ​​है कि आधुनिक प्लेटफार्मों में हार्डवेयर मेमोरी सुरक्षा अन्य प्रक्रियाओं के एड्रेस स्पेस को ओवरराइट करने से यूजरस्पेस प्रोसेस को रोकती है; आपको इसके बजाय एक विभाजन दोष मिलेगा। लेकिन वह सी का हिस्सा नहीं है।
echristopherson

4

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


2

जब आप एक विशाल सरणी को परिभाषित करने की आवश्यकता हो, तो आप डायनामिक मेमोरी आवंटन का उपयोग करना चाहते हैं, int [10000] कह सकते हैं। आप इसे केवल स्टैक में नहीं रख सकते क्योंकि तब, हम्म ... आपको स्टैक ओवरफ्लो मिलेगा।

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


2

(मैं लिख रहा हूं क्योंकि मुझे लगता है कि अब तक के जवाब निशान पर काफी नहीं हैं।)

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

typedef struct listelem { struct listelem *next; void *data;} listelem;

listelem * create(void * data)
{
   listelem *p = calloc(1, sizeof(listelem));
   if(p) p->data = data;
   return p;
}

listelem * delete(listelem * p)
{
   listelem next = p->next;
   free(p);
   return next;
}

void deleteall(listelem * p)
{
  while(p) p = delete(p);
}

void foreach(listelem * p, void (*fun)(void *data) )
{
  for( ; p != NULL; p = p->next) fun(p->data);
}

listelem * merge(listelem *p, listelem *q)
{
  while(p != NULL && p->next != NULL) p = p->next;
  if(p) {
    p->next = q;
    return p;
  } else
    return q;
}

स्वाभाविक रूप से, आप कुछ अन्य कार्यों को पसंद करेंगे, लेकिन मूल रूप से, यह वही है जिसके लिए आपको स्मृति प्रबंधन की आवश्यकता है। मुझे ध्यान देना चाहिए कि "मैनुअल" मेमोरी मैनेजमेंट के साथ कई ट्रिक्स संभव हैं, जैसे,

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

एक अच्छा डिबगर हो जाओ ... शुभकामनाएँ!


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

0

@ यूरो मिशेली

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


0

@ टेड पर्किवल :
... आपको मॉलोक () रिटर्न वैल्यू डालने की जरूरत नहीं है।

आप सही हैं, निश्चित रूप से। मेरा मानना ​​है कि यह हमेशा सच रहा है, हालाँकि मेरे पास जाँच करने के लिए K & R की एक प्रति नहीं है ।

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

यह विशेष रूप से संभावना है यदि आपका संकलक C ++ शैली टिप्पणियों को समझता है।

हाँ ... तुमने मुझे वहाँ पकड़ लिया। मैं C ++ की तुलना में C ++ में बहुत अधिक समय बिताता हूं जो कि ध्यान देने के लिए धन्यवाद।


@echristopherson, धन्यवाद। आप सही हैं - लेकिन कृपया ध्यान दें कि यह क्यू / ए अगस्त 2008 से था, इससे पहले कि स्टैक ओवरफ्लो सार्वजनिक बीटा में भी था। इसके बाद, हम अभी भी यह पता लगा रहे थे कि साइट को कैसे काम करना चाहिए। इस प्रश्न / उत्तर का प्रारूप आवश्यक रूप से एसओ का उपयोग करने के लिए एक मॉडल के रूप में नहीं देखा जाना चाहिए। धन्यवाद!
यूरो माइकेल

आह, यह इंगित करने के लिए धन्यवाद - मुझे महसूस नहीं हुआ कि साइट का पहलू तब भी प्रवाह में था।
ईक्रिस्टोफ़र्सन

0

सी में, आपके पास वास्तव में दो अलग-अलग विकल्प हैं। एक, आप सिस्टम को आपके लिए मेमोरी प्रबंधित करने दे सकते हैं। वैकल्पिक रूप से, आप अपने आप से ऐसा कर सकते हैं। आम तौर पर, आप यथासंभव लंबे समय तक पूर्व से रहना चाहते हैं। हालाँकि, C में स्वतः-प्रबंधित मेमोरी बेहद सीमित है और आपको कई मामलों में मेमोरी को मैन्युअल रूप से प्रबंधित करने की आवश्यकता होगी, जैसे:

ए। आप चाहते हैं कि वैरिएबल फंक्शंस को आउटलाइव करे और आप ग्लोबल वैरिएबल नहीं चाहते हैं। उदाहरण के लिए:

संरचना जोड़ी {
   int val;
   संरचना जोड़ी * अगला;
}

संरचना जोड़ी * new_pair (int val) {
   स्ट्रक्चर पेयर * np = malloc (sizeof (स्ट्रक्चर पेयर));
   np-> वल = वल;
   np-> अगला = NULL;
   वापसी np;
}

ख। आप गतिशील रूप से आवंटित स्मृति चाहते हैं। निश्चित लंबाई के बिना सबसे आम उदाहरण सरणी है:

int * my_special_array;
my_special_array = malloc (sizeof (int) * number_of_element);
के लिए (i = 0; i)

सी। आप वास्तव में गंदा कुछ करना चाहते हैं। उदाहरण के लिए, मुझे कई तरह के डेटा का प्रतिनिधित्व करने के लिए एक संरचना चाहिए और मुझे यूनियन पसंद नहीं है (संघ गंदे दिखते हैं):

संरचना डेटा { int data_type; लंबा data_in_mem; }; संरचना पशु {/ * कुछ * /}; संरचना व्यक्ति {/ * कुछ अन्य चीज * /}; संरचना पशु * read_animal (); संरचना व्यक्ति * read_person (); / * मुख्य * में / संरचना डेटा नमूना; sampe.data_type = input_type; स्विच (INPUT_TYPE) { मामला DATA_PERSON: sample.data_in_mem = read_person (); टूटना; मामला DATA_ANIMAL: sample.data_in_mem = read_animal (); चूक: प्रिंटफ ("ओह होह! मैंने आपको चेतावनी दी है, कि फिर से और मैं आपके ओएस को दोष दूंगा"); }

देखें, कुछ भी मान रखने के लिए एक लंबा मूल्य पर्याप्त है। बस इसे मुक्त करने के लिए याद रखें, या आपको पछतावा होगा। यह C: D में मज़ा करने के लिए मेरी पसंदीदा तरकीबों में से है।

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


"देखें, कुछ भी मानने के लिए एक लंबा मूल्य पर्याप्त है" -: / आप किस बारे में बात कर रहे हैं, अधिकांश प्रणालियों पर एक लंबा मूल्य 4 बाइट्स है, बिल्कुल एक इंट के समान। इसका एकमात्र कारण यह है कि इसमें पॉइंटर्स फिट होते हैं क्योंकि लंबे समय का आकार पॉइंटर के आकार के समान होता है। आपको वास्तव में शून्य * का उपयोग करना चाहिए, हालांकि।
स्कोर_उंडर

-2

ज़रूर। यदि आप एक ऐसी वस्तु बनाते हैं, जो आपके द्वारा उपयोग किए जाने वाले दायरे के बाहर मौजूद है। यहां एक आकस्मिक उदाहरण है (ध्यान रखें कि मेरा सिंटैक्स बंद हो जाएगा; मेरा सी जंग है, लेकिन यह उदाहरण अभी भी अवधारणा को स्पष्ट करेगा):

class MyClass
{
   SomeOtherClass *myObject;

   public MyClass()
   {
      //The object is created when the class is constructed
      myObject = (SomeOtherClass*)malloc(sizeof(myObject));
   }

   public ~MyClass()
   {
      //The class is destructed
      //If you don't free the object here, you leak memory
      free(myObject);
   }

   public void SomeMemberFunction()
   {
      //Some use of the object
      myObject->SomeOperation();
   }


};

इस उदाहरण में, मैं MyClass के जीवनकाल के दौरान SomeOtherClass की एक वस्तु का उपयोग कर रहा हूं। SomeOtherClass ऑब्जेक्ट का उपयोग कई कार्यों में किया जाता है, इसलिए मैंने डायनामिक रूप से मेमोरी आवंटित की है: MyOass को बनाते समय SomeOtherClass ऑब्जेक्ट बनाया जाता है, ऑब्जेक्ट के जीवन पर कई बार उपयोग किया जाता है, और फिर MyClass को मुक्त कर दिया जाता है।

जाहिर है अगर यह वास्तविक कोड होता, तो इस तरह से myObject बनाने के लिए कोई कारण (संभवतः स्टैक मेमोरी की खपत से अलग) नहीं होता, लेकिन इस प्रकार की ऑब्जेक्ट निर्माण / विनाश तब उपयोगी हो जाता है जब आपके पास बहुत सी वस्तुएं हों, और जो आपको ठीक से नियंत्रित करना चाहते हैं जब वे बनाए जाते हैं और नष्ट हो जाते हैं (ताकि आपका एप्लिकेशन अपने पूरे जीवनकाल के लिए 1GB RAM नहीं चूसता है, उदाहरण के लिए), और एक Windowed वातावरण में, यह बहुत अनिवार्य है, जैसा कि आप जो ऑब्जेक्ट बनाते हैं (बटन, कहते हैं) , किसी विशेष फ़ंक्शन (या यहां तक ​​कि वर्ग) के दायरे के बाहर अच्छी तरह से मौजूद होने की आवश्यकता है।


1
हे, हाँ, यह C ++ नहीं है? कमाल है कि किसी को भी इस पर मुझे कॉल करने में पाँच महीने लग गए।
TheSmurf
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.