Dynamic Memory Allocation in C - W3 Coding Club

    Link List

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

    इस समस्या का समाधान करने के लिए कुछ ऐसा किया जा सकता है कि एरे का प्रयोग करने की बजाए जैसे ही नए रिकॉर्ड को स्टोर करना हो वैसे ही केवल उस रिकॉर्ड को स्टोर करने के लिए मैमोरी प्रयोग की जाए। इसे डायनेमिक मैमोरी एलोकेशन कहा जाता है।

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

    Dynamic memory allocation

    कुछ प्रोग्रामिंग लैंग्वेज ऐसी भी होती है जिसमें प्रोग्राम के रन होने के दौरान  Array(एरे)  का आकार बदला जा सकता है। किन्तु 'सी में यह संभव नहीं है। मैमोरी को प्रोग्राम के रन होने के दौरान आरक्षित करने तथा आवश्यकता समाप्त होने पर उसे वापस मुक्त करने के लिए सी में निम्न फंक्शनों का प्रयोग किया जाता है:


      malloc() इस फंक्शन को आरक्षित करवाने वाली मैमोरी का आकार बाइट्स में बताना होता है। यह बताई गई मैमोरी को ऑपरेटिंग सिस्टम से मांग कर उसे आरक्षित कर लेता है तथा आरक्षित मैमोरी की लोकेशन का एड्रेस (पॉइंटर) रिटर्न करता है।
     calloc(...)  इस फंक्शन को आरक्षित करवाने वाली मैमोरी का आकार बाइट्स में बताना होता है। यह बताई गई मैमोरी को ऑपरेटिंग सिस्टम से मांग कर उसे आरक्षित कर लेता है तथा आरक्षित मैमोरी की लोकेशन का एड्रेस (पॉइंटर) रिटर्न करता है। एरे के लिए स्थान आरक्षित करता है। इस फंक्शन को आरक्षित करवाने वाले एरे तथा एरे के प्रत्येक एलीमेंट द्वारा घेरे जाने वाली | मैमोरी (बाइट्स में) बतानी होती है।
    यह बताए गए एरे के लिए मैमोरी को ऑपरेटिंग सिस्टम से मांग कर उसे आरक्षित कर लेता है तथा आरक्षित मैमोरी की लोकेशन का एड्रेस (पॉइंटर) रिटर्न करता है। साथ ही साथ एरे के प्रत्येक एलीमेंट को शून्य से इनीशियलाइज भी कर देता है।
     free(....) इसे एक पॉइंटर इनपुट में दिया जाता है। यह उस पॉइंटर की मैमोरी को मुक्त करते हुए वापस ऑपरेटिंग सिस्टम को लौटा देता है, ताकि अन्य प्रोग्राम उस मैमोरी का उपयोग कर सके।

    प्रोग्राम के रन होने के दौरान मैमोरी एलोकेट करवाने के लिए malloc() का प्रयोग किया जाता है। इसका प्रारूप निम्न प्रकार है:

    pointer variable (type cast) malloc(size in bytes);

    उपरोक्त प्रारूप को टुकड़ों में समझते हैं।

     ....malloc(size in bytes);

    data(डेटा)  को स्टोर करने के लिए हमें जितने bytes(बाइट्स) की आवश्यश्कता होती है वह हमें इस फंक्शन को input(इनपुट) में देनी होती है। यह फक्शन मांगी गई bytes(बाइट्स) को आरक्षित करते हुए उसके प्रथम मैमोरी का एड्रेस (पॉइंटर) रिटर्न करता है। चूंकि जब भी  pointer(पॉइटर) का प्रयोग किया जाता है तो यह भी बताना होता है कि वह pointer(पॉइटर)  किस डेटा टाइप को पॉइंट कर रहा है। 

    यह कार्य टाइप कास्टिंग के माध्यम से निम्न प्रकार किया जाता है:

    (type cast)  malloc(size in bytes);

    अब यह कहा जा सकता है कि उपरोक्त एक्सप्रेशन किसी data type(डेटा टाइप) को पॉइंट करते  हुए    pointer(पॉइटर)  रिटर्न कर रहा है। इसे हमें समान डेटा टाइप को पॉइंट करने वाले पॉइंटर वेरिएबल में स्टोर करवाना होगा। 

     निम्न उदाहरण देखिए

      int *pi:  

    pi(int *) malloc(2);

    उपरोक्त उदाहरण में मैमोरी में 2 bytes(बाइट्स ) आरक्षित करते हुए एक पॉइंटर रिटर्न होगा, जो किसी भी data type(डेटा टाइप) को पॉइंट करते हुए नहीं होगा,  किंतु (int) के माध्यम से वह पॉइंटर अब data type(डेटा टाइप)  को पॉइंट करने वाले पॉइंटर में बदल जाएगा। अतः इस Integer Pointer(इंटीजर पॉइटर) को स्टोर करने के लिए हमने pi पॉइंटर प्रयोग किया है। संपूर्ण रूप से यह कहा जा सकता है कि उपरोक्त उदाहरण में 2 bytes Integer (बाइट्स  इंटीजर ) को स्टोर करने के लिए आरक्षित की जा रही है। अब इस पॉइंटर pi के माध्यम से मैमोरी में एक इंटीजर वैल्यू स्टोर करवाई जा सकती है।

    Example:-

    निम्न उदाहरण में malloc() फंक्शन का प्रयोग समझाया गया है

       
        #include <stdio.h>
        #include <conio.h>
        #include <stdlib.h>
        void main()
        {
            int *pi;
            float *pf;
            pi = (int *malloc(sizeof(int));

            pf = (float *malloc(sizeof(float));       
            *pi = 3948;
            *pf = 248.523;
            printf("\n%d"*pi);
            printf("\n%f"*pf);
            getch();
        }


    Output:-

    3948
    248.522995

    Explain Example:-

    उपरोक्त उदाहरण में एक इंटीजर तथा एक फ्लोट को स्टोर करवाने के लिए malloc() का प्रयोग किया गया है। इस फंक्शन में sizeof (...) ऑपरेटर स्वतः संबंधित डेटा टाइप द्वारा घरे जाने वाली स्पेस बता देगा। यह ध्यान रखें कि malloc() द्वारा रिटर्न की जाने वाली स्पेस मैमोरी में लगातार क्रम में (contiguous) होती है। अतः यदि मैमोरी में मांगी गई स्पेस लगातार क्रम में उपलब्ध नहीं होगी तो malloc() द्वारा null रिटर्न किया जाएगा।

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

     निम्न उदाहरण देखिए  
        int  *pi;    


     pi =  (int * ) malloc(sizeof (int)*5); 

    उपरोक्त उदाहरण में 5 इंटीजर को स्टोर करवाया गया है।

    Example:-

    निम्न उदाहरण में एक से अधिक वैल्यूज़ को स्टोर करने के लिए:-

       
        #include <stdio.h>
        #include <conio.h>
        #include  <stdlib.h>
        void main(){
            int *pi, c=0;
            pi = (int *malloc(sizeof(int)*5);

            while (c<5)
            {
                printf("\nEnter a inteder Value : ");
                scanf("%d",pi);
                pi++;
                c++;
            }
            printf("\n\nYou Entered following numbers : ");       
            c = 0;
            pi = pi-5;
            while (c<5)
            {
                printf("\n%d",*pi);
                pi++;
                c++;
            }
            getch();
        }

    Output:-

    Enter a inteder Value : 12
    Enter a inteder Value : 23
    Enter a inteder Value : 43
    Enter a inteder Value : 45
    Enter a inteder Value : 65

    You Entered following numbers : 
    12
    23
    43
    45
    65

    Explain Example:-

    उपरोक्त उदाहरण में 5 इंटीजर के लिए Memory Allocation(मैमोरी एलोकेशन ) करवाया गया है तथा प्रथम मैमोरी एड्रेस को पॉइंटर    pi   में स्टोर करवा लिया गया है। तत्पश्चात् एक लूप 5 बार चलाया गया है। जब लूप प्रथम बार रन होगा तो pl प्रथम एड्रेस को पॉइट करेगा।  scanf()     में pi के पहले & ऑपरेटर का प्रयोग नहीं किया गया है, क्योंकि pi स्वयं एक एड्रेस ही है। तत्पश्चात् में इंक्रीमेंट किया गया है, जिससे   pi    द्वितीय वैल्यू के लिए आरक्षित स्पेस को पॉइंट करने लगेगा। अगले लूप में जब इनपुट लिया जाएगा तो वह वैल्यू द्वितीय वैल्यू के लिए आरक्षित स्थान पर स्टोर हो जाएगी। यह प्रक्रिया 5 बार दोहराई जाएगी। प्रथम लूप से बाहर आने पर पॉइंटर अंतिम वैल्यू के लिए आरक्षित को पॉइट करने लगेगा। चूंकि हमें वापस प्रथम वैल्यू से प्रिंट करवाना है अत:   pi = pi-5   के माध्यम से pi को वापस प्रथम वैल्यू के लिए आरक्षित स्थान पर पॉइंट करवा दिया गया है। द्वितीय लूप में इनपुट की गई पांचों वैल्यूज प्रिंट हो जाएंगी।



    उपरोक्त उदाहरण में   pi = (int *) malloc(sizeof (int)*5)   के तुरंत बाद निम्न स्टेटमेंट्स जोड़े जा सकते थे:

        
        if (pi == NULL)
        {
            printf("Memory alloaction failed");
            exit (1);
        }

    उपरोक्त स्टेटमेंट यह जांच कर रहा है कि क्या malloc() सफलतापूर्वक Memory Allocate(मैमोरी एलोकेट)  करवा चुका है। यदि नहीं तो pi में null स्टोर हो जाएगा। यदि ऐसा है तो program(प्रोग्राम) का प्रवाह इस ब्लॉक में प्रवेश करते हुए exit(.. ) के माध्यम से प्रोग्राम को समाप्त कर देगा। 

    Free unwanted memory

    जब भी किसी वेरिएबल के लिए Memory Allocate(मैमोरी एलोकेट)  होती है तो वह संबंधित block(ब्लॉक) या प्रोग्राम की समाप्ति पर ही मुक्त होती है। अर्थात उस समयावधि में उस मैमोरी का प्रयोग कोई अन्य प्रोग्राम नहीं कर सकता है। 

    ऐसे वेरिएबल जिनकी हमें प्रोग्राम में आगे आवश्यकता नहीं हो, को मुक्त कर दिया जाना चाहिए। Memory को मुक्त करने के लिए     free( )     फंक्शन प्रयोग किया जाता है, जिसका प्रारूप निम्न प्रकार हैं 👇👇

    free(pointer_variable)

    उपरोक्त प्रारूप में pointer_variable उस मैमोरी स्थान को इंगित करता है, जिसे मुक्त किया जाना है।

    int * pi;
    pi = (int * ) malloc(sizeof(int)*5);
    . . . . .
    free(pi);

    उपरोक्त उदाहरण में   free(pi)   5 इंटीजर संख्याओं द्वारा घेरे जाने वाली मैमोरी को मुक्त कर देगा। 

    Example:-

     निम्न उदाहरण में Memory Allocation(मैमोरी एलोकेशन) का कार्य स्ट्रक्चर पर किया जा रहा है।


        #include <stdio.h>
        #include <conio.h>
        #include <stdlib.h>
        struct emp
        {
            char name[20];
            int age;
        };
        typedef struct emp Emp;

        void main()
        {
            Emp *pEmp;
            pEmp = (Emp *)malloc(sizeof(Emp));
            if (pEmp == NULL)
            {
                exit(1);
            }
            printf("\nEnter Employee Name : ");
            scanf("%s", pEmp->name);
            printf("\nEnter Employee Age : ");
            scanf("%d", pEmp->age);

            printf("\nName : %s,", pEmp->name);
            printf("\nAge : %d,", pEmp->age);
            getch();
        }

    Output:-

    Enter Employee Name : Mukesh
    Enter Employee Age : 18

    Name : Mukesh
    Age : 18

    Explain Example:-

    उपरोक्त उदाहरण में चूंकि Structure Member को pointer के माध्यम से प्रयोग किया जा रहा है, अतः डॉट(.) की जगह पर (->) का प्रयोग किया जाता हैं। 

    Post a Comment

    0 Comments