C भाषा में डायनामिक मेमोरी आवंटन: malloc(), calloc()

⚡ स्मार्ट सारांश

सी भाषा में डायनेमिक मेमोरी एलोकेशन, stdlib.h लाइब्रेरी के malloc(), calloc(), realloc() और free() फ़ंक्शन का उपयोग करके रनटाइम पर हीप मेमोरी को आरक्षित और रिलीज़ करता है, जिससे प्रोग्राम निष्पादन से पहले आवश्यकताओं के अज्ञात होने पर भी एरे और संरचनाओं के आकार को लचीले ढंग से निर्धारित कर सकते हैं।

  • 🧠 स्टैक बनाम हीप: बेसिक वेरिएबल ऑटोमैटिक स्टैक का उपयोग करते हैं, जबकि डायनेमिक मेमोरी हीप पर रहती है और पॉइंटर्स के माध्यम से मैन्युअल रूप से प्रबंधित की जाती है।
  • 📦 मॉलॉक(): अनुरोधित बाइट आकार का एक अपरिभाषित ब्लॉक आरक्षित करता है और एक शून्य पॉइंटर लौटाता है, या मेमोरी अपर्याप्त होने पर NULL लौटाता है।
  • 🔢 कॉलोक(): यह फ़ंक्शन एरे के लिए कई ब्लॉक आवंटित करता है, प्रत्येक बाइट को शून्य पर सेट करता है, और पहले ब्लॉक का पॉइंटर लौटाता है।
  • 🔄 realloc(): यह मौजूदा ब्लॉक के आकार को छोटा या बड़ा करता है, साथ ही मूल सामग्री को संरक्षित रखते हुए उसे संभवतः एक नए स्थान पर ले जाता है।
  • 🧹 मुक्त(): मेमोरी को हीप में वापस लौटाता है; मेमोरी लीक को रोकने के लिए प्रत्येक malloc() या calloc() के लिए एक मिलान free() की आवश्यकता होती है।
  • 🤖 एआई सहायता: एआई सहायक और गिटहब कोपायलट आवंटन कोड का मसौदा तैयार करते हैं और छूटे हुए फ्री() कॉल और लीक को चिह्नित करते हैं।

सी में गतिशील मेमोरी आवंटन

सी में मेमोरी प्रबंधन कैसे काम करता है?

जब आप किसी बुनियादी डेटा प्रकार का उपयोग करके किसी वेरिएबल को घोषित करते हैं, तो C कंपाइलर स्वचालित रूप से स्टैक नामक मेमोरी पूल में वेरिएबल के लिए मेमोरी स्पेस आवंटित करता है।

उदाहरण के लिए, एक फ्लोट वेरिएबल को घोषित करते समय आमतौर पर 4 बाइट्स (प्लेटफ़ॉर्म के अनुसार) लगते हैं। हम नीचे दिए गए उदाहरण में दिखाए गए अनुसार sizeof ऑपरेटर का उपयोग करके इस जानकारी को सत्यापित कर सकते हैं।

#include <stdio.h>
int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0;}

उत्पादन हो जाएगा:

 The size of float is 4 bytes

इसके अलावा, निर्दिष्ट आकार वाली एक सरणी को मेमोरी के सन्निहित ब्लॉकों में आवंटित किया जाता है, प्रत्येक ब्लॉक में एक तत्व का आकार होता है:

#include <stdio.h>
int main() { float arr[10];
printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}

परिणाम है:

 The size of the float array with 10 element is 40

अब तक हमने जो सीखा है, उसके अनुसार किसी बेसिक डेटा टाइप या ऐरे को डिक्लेयर करते समय मेमोरी का मैनेजमेंट ऑटोमैटिकली हो जाता है। हालांकि, C में मेमोरी एलोकेट करने की एक प्रक्रिया है, जिसकी मदद से आप ऐसा प्रोग्राम बना सकते हैं जिसमें ऐरे का साइज़ प्रोग्राम रन होने तक (रनटाइम) तय नहीं होता। इस प्रक्रिया को "डायनेमिक मेमोरी एलोकेशन" कहते हैं।

सी में गतिशील मेमोरी आवंटन

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

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

लाइब्रेरी में डायनामिक मेमोरी प्रबंधन के लिए जिम्मेदार फ़ंक्शन हैं।

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

आइये उपरोक्त कार्यों और उनके अनुप्रयोग पर चर्चा करें

C में malloc() फ़ंक्शन

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

malloc() फ़ंक्शन का सिंटैक्स:

ptr = (cast_type *) malloc (byte_size);

यहाँ,

  • ptr cast_type का सूचक है.
  • C malloc() फ़ंक्शन byte_size की आवंटित मेमोरी के लिए एक पॉइंटर लौटाता है।

malloc() का उदाहरण:

Example: ptr = (int *) malloc (50)

जब यह कथन सफलतापूर्वक निष्पादित होता है, तो 50 बाइट्स का मेमोरी स्पेस आरक्षित हो जाता है। आरक्षित स्थान के पहले बाइट का पता int प्रकार के पॉइंटर ptr को असाइन किया जाता है।

एक अन्य उदाहरण पर विचार करें:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

आउटपुट:

Value of the 6th integer is 480

सी malloc() फ़ंक्शन

  1. ध्यान दें कि sizeof(int) के बजाय sizeof(*ptr) का उपयोग किया गया है ताकि बाद में *ptr घोषणा को किसी भिन्न डेटा प्रकार में टाइपकास्ट किए जाने पर कोड को अधिक मजबूत बनाया जा सके।
  2. यदि मेमोरी पर्याप्त नहीं है तो आवंटन विफल हो सकता है। इस मामले में, यह एक NULL पॉइंटर लौटाता है। इसलिए, आपको NULL पॉइंटर की जांच करने के लिए कोड शामिल करना चाहिए।
  3. ध्यान रखें कि आवंटित मेमोरी सन्निहित है और इसे एक सरणी के रूप में माना जा सकता है। हम कोष्ठक [ ] का उपयोग करने के बजाय सरणी तत्वों तक पहुँचने के लिए पॉइंटर अंकगणित का उपयोग कर सकते हैं। हम सरणी तत्वों को संदर्भित करने के लिए + का उपयोग करने की सलाह देते हैं क्योंकि वृद्धि ++ या += का उपयोग करने से सरणी द्वारा संग्रहीत पता बदल जाता है। सूचक.

Malloc() फ़ंक्शन का उपयोग कैरेक्टर डेटा प्रकार के साथ-साथ संरचनाओं जैसे जटिल डेटा प्रकारों के साथ भी किया जा सकता है।

C में free() फ़ंक्शन

स्मृति के लिए चर संकलन समय पर स्वचालित रूप से डी-एलोकेट हो जाता है। गतिशील मेमोरी आवंटन में, आपको मेमोरी को स्पष्ट रूप से डी-एलोकेट करना होगा। यदि ऐसा नहीं किया जाता है, तो आपको आउट ऑफ मेमोरी त्रुटि का सामना करना पड़ सकता है।

C में मेमोरी को मुक्त करने/डीएलोकेट करने के लिए free() फ़ंक्शन का उपयोग किया जाता है। अपने प्रोग्राम में मेमोरी को मुक्त करके, आप बाद में उपयोग के लिए अधिक मेमोरी उपलब्ध कराते हैं।

उदाहरण के लिए:

#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
  *(ptr + 2) = 50;
  printf("Value of the 2nd integer is %d",*(ptr + 2));
}
free(ptr);
}

आउटपुट:

 Value of the 2nd integer is 50

C में calloc() फ़ंक्शन

C calloc() फ़ंक्शन का मतलब है कॉन्टिगुअस एलोकेशन। इस फ़ंक्शन का उपयोग मेमोरी के कई ब्लॉक आवंटित करने के लिए किया जाता है। यह एक डायनेमिक मेमोरी एलोकेशन फ़ंक्शन है जिसका उपयोग एरे और स्ट्रक्चर जैसे जटिल डेटा संरचनाओं को मेमोरी आवंटित करने के लिए किया जाता है।

Malloc() फ़ंक्शन का उपयोग मेमोरी स्पेस के एक ब्लॉक को आवंटित करने के लिए किया जाता है जबकि C में calloc() का उपयोग मेमोरी स्पेस के कई ब्लॉक को आवंटित करने के लिए किया जाता है। calloc() फ़ंक्शन द्वारा आवंटित प्रत्येक ब्लॉक समान आकार का होता है।

calloc() फ़ंक्शन का सिंटैक्स:

ptr = (cast_type *) calloc (n, size);

उपरोक्त कथन का उपयोग समान आकार के n मेमोरी ब्लॉक आवंटित करने के लिए किया जाता है।

मेमोरी स्पेस आवंटित होने के बाद, सभी बाइट्स को शून्य पर आरंभीकृत कर दिया जाता है।

वह पॉइंटर जो वर्तमान में आवंटित मेमोरी स्थान के प्रथम बाइट पर है, लौटा दिया जाता है।

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

calloc() का उदाहरण:

नीचे दिया गया प्रोग्राम एक अंकगणितीय अनुक्रम का योगफल गणना करता है।

#include <stdio.h>
    int main() {
        int i, * ptr, sum = 0;
        ptr = calloc(10, sizeof(int));
        if (ptr == NULL) {
            printf("Error! memory not allocated.");
            exit(0);
        }
        printf("Building and calculating the sequence sum of the first 10 terms \ n ");
        for (i = 0; i < 10; ++i) { * (ptr + i) = i;
            sum += * (ptr + i);
        }
        printf("Sum = %d", sum);
        free(ptr);
        return 0;
    }

रिजल्ट:

Building and calculating the sequence sum of the first 10 terms
Sum = 45

calloc() बनाम malloc(): मुख्य अंतर

इनके बीच मुख्य अंतर निम्नलिखित है malloc() बनाम calloc() सी में:

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

सी में calloc() द्वारा आवंटित मेमोरी ब्लॉक को हमेशा शून्य पर आरंभीकृत किया जाता है, जबकि सी में फंक्शन malloc() में, इसमें हमेशा एक कचरा मान होता है।

C में realloc() फ़ंक्शन

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

realloc() का उपयोग पहले से आवंटित मेमोरी के आकार को कम करने के लिए भी किया जा सकता है।

realloc() फ़ंक्शन का सिंटैक्स:

ptr = realloc (ptr,newsize);

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

realloc() का उदाहरण:

#include <stdio.h>
int main () {
   char *ptr;
   ptr = (char *) malloc(10);
   strcpy(ptr, "Programming");
   printf(" %s,  Address = %u\n", ptr, ptr);

   ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size
   strcat(ptr, " In 'C'");
   printf(" %s,  Address = %u\n", ptr, ptr);
   free(ptr);
   return 0;
}

जब भी C में realloc() के परिणामस्वरूप कोई ऑपरेशन असफल होता है, तो यह शून्य पॉइंटर लौटाता है, और पिछला डेटा भी मुक्त हो जाता है।

सी में गतिशील सारणी

सी में डायनेमिक ऐरे तत्वों की संख्या को आवश्यकतानुसार बढ़ाने की अनुमति देता है। सी डायनेमिक ऐरे का उपयोग कंप्यूटर विज्ञान एल्गोरिदम में व्यापक रूप से किया जाता है।

निम्नलिखित प्रोग्राम में, हमने एक डायनामिक सरणी बनाई है और उसका आकार बदला है C

#include <stdio.h>
    int main() {
        int * arr_dynamic = NULL;
        int elements = 2, i;
        arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks
        for (i = 0; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        elements = 4;
        arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); //reallocate 4 elements
        printf("After realloc\n");
        for (i = 2; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        free(arr_dynamic);
    }

स्क्रीन पर सी डायनेमिक ऐरे प्रोग्राम का परिणाम:

 
arr_dynamic[0]=0
arr_dynamic[1]=1
After realloc
arr_dynamic[0]=0
arr_dynamic[1]=1
arr_dynamic[2]=2
arr_dynamic[3]=3

अक्सर पूछे जाने वाले प्रश्न

जब malloc() या calloc() द्वारा ली गई हीप मेमोरी को कभी रिलीज़ नहीं किया जाता है, तो मेमोरी लीक होती है। इससे बचने के लिए, प्रत्येक एलोकेशन के साथ ब्लॉक की आवश्यकता समाप्त होने पर एक संबंधित free() कॉल को जोड़ें।

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

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

नहीं। एक ही पते पर दो बार free() फ़ंक्शन को कॉल करना डबल फ्री कहलाता है और इससे अनिश्चित व्यवहार उत्पन्न हो सकता है या सिस्टम क्रैश हो सकता है। पहले free() फ़ंक्शन के बाद पॉइंटर को NULL पर सेट करने से बाद के सभी free() फ़ंक्शन हानिरहित हो जाते हैं।

realloc(NULL, size) malloc(size) की तरह ही काम करता है और एक नया ब्लॉक आवंटित करता है। realloc(ptr, 0) ब्लॉक को मुक्त करता है, इसलिए मूल पॉइंटर को ओवरराइट करने के बजाय हमेशा लौटाए गए पॉइंटर को कैप्चर करें।

Valgrind, AddressSanitizer और Dr. Memory जैसे उपकरण track प्रत्येक आवंटन और रिपोर्ट ब्लॉक जो कभी मुक्त नहीं किए गए थे, साथ ही सटीक पंक्ति, helping आप रिलीज से पहले लीकेज का पता लगाते हैं।

जी हां। एक एआई कोडिंग सहायक प्रॉम्प्ट से malloc(), calloc() और free() अनुक्रम तैयार करता है, पॉइंटर त्रुटियों की व्याख्या करता है और छूटे हुए free() कॉल को चिह्नित करता है। जेनरेट किए गए कोड पर भरोसा करने से पहले हमेशा उसे कंपाइल और टेस्ट करें।

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

इस पोस्ट को संक्षेप में इस प्रकार लिखें: