Pointer Arithmetic

    जिस प्रकार अन्य  variables(वेरिएबलो)  के साथ Arithmetic operation(गणितीय कार्यों) को किया जा सकता है ठीक उसी प्रकार पॉइन्टर वेरिएबल पर भी कुछ गणितीय कार्य किए जा सकते हैं। 

    पॉइन्टर पर कुछ Automatic operation(अर्थमैटिक ऑपरेशन) किए जा सकते हैं। इसके साथ प्रयोग में आने वाले Operators(ऑपरेटरों) में +, ++, -, -- ऑपरेटर शामिल है। इन्हीं ऑपरेटर को प्रयोग करने हेतु नियम इस प्रकार है:- 

    1. दो Operators(ऑपरेटरों) को जोड़ा नहीं जा सकता है,  किंतु  pointer(पॉइन्टर)  में integer value(इंटीरिजर वैल्यू) जोड़ी जा सकती है। 
    2. दो ऑपरेटरों को घटाया जा सकता है। इस प्रकार दो Operators(ऑपरेटरों) के मध्य स्थित bytes( बाइट्स) की संख्या ज्ञात की जा सकती हैं। 
    3. दो Pointer(पॉइन्टर) को आपस में गुणा अथवा विभाजित नहीं किया जा सकता हैं।
    4. Pointer(पॉइन्टर) में float को नहीं जोड़ा अथवा घटाया जा सकता है।  किंतु ऐसा  integer(इंटीरिजर) के साथ किया जा सकता हैं। 
    5. एक प्रकार के pointer variable(पॉइन्टर वेरिएबल) में दूसरे प्रकार के pointer(पॉइन्टर)  को store(स्टोर) नहीं किया जा सकता हैं। 
    6. Arithmetic operator(अर्थमैटिक ऑपरेटर) के अलावा relational operator(रिलेशनल ऑपरेटर) ओं का प्रयोग भी operator(ऑपरेटर) पर किया जा सकता हैं। जैसे p1<p2 या p1==p2, जिसमें p1 तथा p2 pointer(पॉइन्टर) हैं। 

    किसी pointer(पॉइन्टर) के साथ Increment or  Decrement operator(इंक्रीमेंट अथवा  डिक्रिमेंट ऑपरेटर) का प्रयोग किया जा सकता हैं। उदाहरण के लिए p1++ या --p2 pointer(पॉइन्टर) पर उचित प्रयोग हैं। 

    किंतु pointer(पॉइन्टर) के साथ इसके प्रयोग में प्वाइंटर की वैल्यू में वृद्धि अथवा कमी कितनी होगी  scale-factor(स्केल-फैक्टर) पर निर्भर करता हैं। 
    उदाहरण के लिए यदि किसी  integer pointer(इंटीरियर पॉइन्टर) p1 में 32416 स्टोर है तो p1++ के कारण से उस पॉइन्टर की वैल्यू 32417 होने की बजाए 32418 हो जाएगी। इसका कारण यह है कि प्रत्येक डाटा टाइप का scale-factor(स्केल-फैक्टर) उसके द्वारा घेरे जाने वाली मेमोरी के बराबर होता हैं। 

    उपरोक्त उदाहरण में यदि पॉइन्टर p1 का data-type(डाटा टाइप) float(फ्लोट) होता तो p++ के कारण उसकी वैल्यू 32416 से 32420 हो जाती।  

       float f = 12.45*pf;
       pf = &f; //suppose address of f is : 42874
       pf = pf+1// now it will be 425878
       pf = pf+2  // now it will be 42886

     ऊपर दिए गए   उदाहरण में pf में 2 से increment(इंक्रीमेंट) किया गया हैं। ऐसे में चुंकी float 4 बाइट घेरता है, अतः increment (4 x 2) यानी 8 से होगा। 

    Example:-

    इस उदाहरण में पॉइन्टर  के माध्यम से अन्य वेरिएबल की  वैल्यू का प्रयोग किया गया हैं। 


       #include <stdio.h>
       #include <conio.h>
       void main()
       {
          int a = 10;
          int b = 5;
          int *p;
          int *q;
          p = &a;
          q = &b;
          printf("\nValue of a is %d"*p);
          printf("\nValue of b is %d"*q);
          printf("\n Sum of a and b is %d", (*+ *q));        
          getch();
       }

    Output:-

    Value of a is 10
    Value of b is 5
    Sum of a and b is 15

    Explain Example:-

    ऊपर दिए गए उदाहरण में p = &a वेरिएबल a का एड्रेस(memory location) पॉइन्टर p में स्टोर करवाया गया हैं, तथा बाद में *p के माध्यम से वेरिएबल a की वैल्यू प्रिंट कराई गई हैं। 

    Array and Pointers

    एरे को हम पूर्व के अध्याय में समझ चुके हैं उसे प्रयोग करने के तरीके भी उसी अध्याय में समझाएं गए थे। एरे  को pointer(पॉइन्टर) के माध्यम से भी प्रयोग किया जा सकता है। एरे  को प्रयोग करने का अतिरिक्त तरीका प्रदान करता है। एरे  को प्रयोग करते हुए आप अप्रत्यक्ष रूप से pointer(पॉइन्टर) को प्रयोग कर चुके हैंं। 

     जब किसी एरे को declare(डिक्लेअर) किया जाता है तो 'C' का compiler(कंपाइलर) उस एरे  के नाम का  constant pointer(कांस्टेंट पॉइन्टर) बना देता है।  जिसका मान प्रोग्राम के रन होने के दौरान बदला नहीं जा सकता हैं। इस constant pointer(कांस्टेंट पॉइन्टर)  में एरे  के प्रथम element(एलिमेंट) का एड्रेस स्टोर हो जाता हैं। 

    इसे समझने के लिए मान लेते हैं कि हमने एक एरे  निम्न प्रकार से declare(डिक्लेअर) किया है: 

     int a[5] = {1,3,2,6,5}; 

    मान लेते हैं कि उपरोक्त पहले एलिमेंट का एड्रेस 32416 है, तो compiler(कंपाइलर) इस declaration(डिक्लेरेशन) के दौरान एक constant pointer(कांस्टेंट प्वाइंटर) a भी बना देता है तथा उसमें पहले तत्व का एड्रेस (32416) स्टोर कर देता हैं। 

    अर्थात किसी pointer variable(पॉइन्टर वेरिएबल) में एरे के पहले element(एलिमेंट) के address को निम्न में से किसी एक प्रकार से स्टोर किया जा सकता है। 

     ptr = a 

        या 

     ptr = &a[0] 

    पहले एलिमेंट के एड्रेस को प्वाइंटर के बाद pointer वेरिएबल में increment(इंक्रीमेंट) करके Array के अगले एलिमेंट को प्रयोग में लाया जा सकता है।  


       #include <stdio.h>
       #include <conio.h>
       void main()

       {
          int a[3= {324};
          int *p;
          p = a;
          printf("Value of a[0] is %d at address %u"*p, p);
          p++;
          printf("\nValue of a[1] is %d at address %u"*p, p);         
          p++;
          printf("\nValue of a[2] is %d at address %u"*p, p);
          getch();
       }

    Output:-

    Value of a[0] is 3 at address 6422208
    Value of a[1] is 2 at address 6422212
    Value of a[2] is 4 at address 6422216

    Explain Example:-

    उपरोक्त उदाहरण में p++ का प्रयोग करने से वह  अगली वैल्यू को पॉइंट करने लगा। यह ध्यान दें कि पॉइन्टर p चूंकि इंटीरियर पॉइंट पर है, अतः p++ करने पर उसमें इंक्रीमेंट 64x के अनुशार  4 और 32x के अनुशार  2   से होगा। 

    ऊपर दिया गया उदाहरण 64x कंपाइलर में किया गया है, अतः इंक्रीमेंट 4 से हुआ है।
    क्योंकि 64x कंपाइलर के अनुसार int मेमोरी में 4 byte जगह लेता हैं।

    Example:- 

    ऊपर दिए गए उदाहरण को इस 👇👇 प्रकार से भी किया जा सकता है। 

       #include <stdio.h>
       #include <conio.h>
       void main()
       {
          int a[3= {324};
          int c;
          int *p;
          p = a; // or p = &a[0]
          for (c = 0; c < 3; c++)
          {
             printf("\nValue of a[%d] is %d at address %u", c, *p, p);
             p++;
          }
          getch();
       }

    Output:-

    Value of a[0] is 3 at address 6422204
    Value of a[1] is 2 at address 6422208
    Value of a[2] is 4 at address 6422212

    Example:-

    ऊपर दिए गए उदाहरण को इस 👇👇 प्रकार से भी किया जा सकता है। 


       #include <stdio.h>
       #include <conio.h>
       void main()
       {
          int a[3][2= {35342187597365728};
          int r, c;
          int *p;
          p = a ;
          for (r = 0; r < 3; r++)
          {
             for (c = 0; c < 2; c++)
             {
                printf("\nValue of a[%d][%d] is %d at address %u", r, c, *p, p);
                p ++;
             }
          }
          getch();
       }

    Output:-

    Value of a[0][0] is 353 at address 6422188
    Value of a[0][1] is 42 at address 6422192
    Value of a[1][0] is 187 at address 6422196
    Value of a[1][1] is 597 at address 6422200
    Value of a[2][0] is 3657 at address 6422204
    Value of a[2][1] is 28 at address 6422208

    Array of Pointer

    जिस प्रकार किसी डाटा को एरिया में स्टोर किया जा सकता है उसी प्रकार विभिन्न ऑपरेटर्स को भी एरिया में स्टोर किया जा सकता है। इस प्रकार बने प्वाइंटर के एरे (Array of Pointers) में विभिन्न ऑपरेटर मेमोरी की बिल्कुल अलग-अलग लोकेशन को  पॉइंट करते हुए हो सकते हैं।

    Example:-


       #include <stdio.h>
       #include <conio.h>
       void main()
       {
          int a[3= {324};
          int c;
          int *p[3];
          for (c = 0; c < 3; c++)
          {
             p[c] = &a[c];
          }
          for (c = 0; c < 3; c++)
          {
             printf("\n Value of a[%d] is %d and Address is %u", c, a[c], p[c]);
          }
          getch();
       }

    Output:-

    Value of a[0] is 3 and Address is 6422208
    Value of a[1] is 2 and Address is 6422212
    Value of a[2] is 4 and Address is 6422216

    Explain Example:-

    इस उदाहरण में int *p[3] में चूंकि [] तथा * दो ऑपरेटर प्रयोग किए गए हैं। चूंकि [] ऑपरेटर की प्रेसिडेंट अधिक होती है अतः पहले [] ऑपरेटर कार्य करेगा तथा उसके बाद * ऑपरेटर कार्य करेगा। अतः इसे यह कहा जा सकता है कि p एक एरे है - प्वाइंटर्स का। 

    वहीं अगर उपरोक्त स्टेटमेंट को int (*p)[3] के रूप में डिक्लेअर किया जाए तो इसे निम्न प्रकार समझा जाएगा - p एक pointer है जो 3 एलिमेंट वाले एरे की तरफ  इंगित कर रहा है। 

    Pointer to Pointer

    जिस प्रकार एक वेरिएबल के एड्रेस को pointer(पॉइन्टर) में स्टोर किया जा सकता है, ठीक उसी प्रकार एक pointer(पॉइन्टर) के एड्रेस को भी अन्य pointer(पॉइन्टर) में स्टोर किया जा सकता है जिसे pointer to pointer(पॉइन्टर टू पॉइन्टर) कहते हैं। 

    अन्य शब्दों में हम यह कह सकते हैं कि pointer to pointer(पॉइन्टर टू पॉइन्टर) वेरिएबल होता है जो किसी अन्य pointer के एड्रेस को स्टोर करता है। जिसे निम्न प्रकार से declare(डिक्लेअर) किया जा सकता है:-

     data_type *pointer_to_ponter_name; 

    Example:-

     && int **ptr; 

    pointer to pointer, query boat, queryboat

    ऊपर दिए गए image में एक  pointer to pointer(पॉइन्टर टू पॉइन्टर) है, जो पॉइन्टर p को इंगित  कर रहा हैं। 

    Example:-

    प्रस्तुत उदाहरण में pointer to pointer(पॉइन्टर टू पॉइन्टर) का प्रयोग करते हुए वैल्यू को प्रिंट करवाया गया हैं। 


       #include <stdio.h>
       #include <conio.h>
       void main()
       {
          int a;
          int *p;
          int **q;
          a = 10;
          p = &a; // storing address of a in pointer p
          q = &a; // storing Address of pointer p in pointer q
          printf("\n Address of a is %u ",p);
          printf("\n Value  of a is %d",*p);
          printf("\n Address  of q is %u",q);
          printf("\n Value  of q is %d",*q);
          printf("\n Address  of p is %u",&q);
          printf("\n Value  of p is %d",q);
          getch();
       }

    Output:-

    Address of a is 6422216
    Value of a is 10
    Address of q is 6422216
    Value of q is 10
    Address of p is 6422212
    Value of p is 6422216

    Explain Example:-

    उपरोक्त उदाहरण में int **q कंपाइलर को यह बताता है कि इसमें स्टोर होने वाली वैल्यू जिस लोकेशन को पॉइंट करेगी, उसमें भी एक pointer(पॉइन्टर) ही स्टोर मिलेगा।
    उपरोक्त उदाहरण में दर्शाई गए आउटपुट में मेमोरी लोकेशन किसी अन्य कंप्यूटर पर अलग हो सकती है। यह आउटपुट 64बीट के अनुसार हैं।

    Important points of pointer

    1. Pointer(पॉइन्टर) से ऐसे ऐसे विशेष वेरिएबल से हैं जिसमें सामान्य वैल्यू की जगह मेमोरी की किसी लोकेशन का एड्रेस स्टोर होता हैं।
    2. पॉइंटर्स को प्रयोग करने के विभिन्न कारण है जिनमें से प्रमुख निम्न प्रकार है:-
    3. इसके माध्यम से किसी hidden(हिडन) वेरिएबल को भी प्रयोग किया जा सकता हैं।
      • इसे प्रयोग करते हुए मेमोरी का उपयोग(consumption) कम किया जा सकता हैं।
      • यह प्रोग्राम के रन होने की गति बढ़ाने में सहायक होते हैंं।
      • इसके माध्यम से प्रोग्राम की जटिलता को कम किया जा सकता हैं।
      • इसके माध्यम से किसी function(फंक्शन) से एक से अधिक वैल्यू return(रिटर्न) करवाई जा सकती हैं।
      • यह multi-Dimensional Array(मल्टीडाइमेंशनल एरे) को प्रयोग करने का बेहतर तरीका प्रदान करता हैं।
      • किसी वेरिएबल के नाम के पहले &(जिसे एड्रेस ऑफ ऑपरेटर भी कहा जाता है) ऑपरेटर लगाने से उस वेरिएबल का मेमोरी ऐड्रेस ज्ञात हो जाता हैं।
    4. पॉइन्टर हमेशा Unsigned int ही होता है, जो कि सामान्यतः 2 बाइट (32 बिट के अनुसार) स्पेस ही लेता है।
    5. किसी वेरिएबल के नाम के पहले &(जिसे एड्रेस ऑफ ऑपरेटर भी कहा जाता है) ऑपरेटर लगाने से उस वेरिएबल का मेमोरी ऐड्रेस ज्ञात हो जाता हैं।
    6. पॉइन्टर को initialize(इनिशियलाइज) करने के लिए उसमें मेमोरी Address(एड्रेस) स्टोर करना होता हैं।
    7. किसी प्वाइंटर द्वारा वेरिएबल की वैल्यू को प्रयोग करने के लिए pointer variable(पॉइन्टर वेरिएबल) के नाम से पूर्व *Operator(ऑपरेटर) लगा दिया जाता हैं। इस *Operator(ऑपरेटर) को समझने की दृष्टि से value at(वैल्यु एट) भी कहा जा सकता हैं। किंतु पॉइन्टर को इनिशियलाइज(initialize) करते समय पॉइन्टर के नाम के पहले * नहीं लगाया जाता हैं।
    8. पॉइन्टर हमेशा Unsigned int ही होता है, जो कि सामान्यतः 2 बाइट (32 बिट के अनुसार) स्पेस ही लेता है।
    9. Pointer(पॉइन्टर) में increment(इंक्रीमेंट) करने पर उसकी वैल्यू में कितनी वृद्धि होगी यह scale factor(स्केल फैक्टर) पर निर्भर करता हैं। प्रत्येक data-type का scale factor(स्केल फैक्टर) उसके द्वारा घिरे जाने वाली मेमोरी के बराबर होता हैं।
    10. जब किसी एरे को declare(डिक्लेअर) किया जाता है तो "C" compiler ("सी" कंपाइलर) उस array(एरे) के नाम का constant pointer(कांस्टेंट पॉइन्टर) बना देता हैं। जिसका मान प्रोग्राम के रन होने के दौरान बदला नहीं जा सकता है। इस constant pointer(कांस्टेंट पॉइन्टर) में एरे के प्रथम element(एलिमेंट) का address(एड्रेस) स्टोर हो जाता हैं।