c++ - पॉइंटर्स का उपयोग क्यों करें?




pointers (12)

  1. पॉइंटर्स आपको कई स्थानों से स्मृति में एक ही स्थान को संदर्भित करने की अनुमति देता है। इसका मतलब है कि आप एक स्थान पर स्मृति अपडेट कर सकते हैं और आपके प्रोग्राम में किसी अन्य स्थान से परिवर्तन देखा जा सकता है। आप अपने डेटा संरचनाओं में घटकों को साझा करने में सक्षम होने से अंतरिक्ष भी बचाएंगे।
  2. आपको पॉइंटर्स का उपयोग किसी भी स्थान पर करना चाहिए जहां आपको स्मृति में किसी विशिष्ट स्थान पर पता लगाने और पास करने की आवश्यकता है। आप सरणी को नेविगेट करने के लिए पॉइंटर्स का भी उपयोग कर सकते हैं:
  3. एक सरणी संगत स्मृति का एक ब्लॉक है जिसे एक विशिष्ट प्रकार के साथ आवंटित किया गया है। सरणी के नाम में सरणी के प्रारंभिक स्थान का मान होता है। जब आप 1 जोड़ते हैं, तो यह आपको दूसरे स्थान पर ले जाता है। यह आपको लूप लिखने की अनुमति देता है जो सरणी तक पहुंचने के लिए स्पष्ट काउंटर के बिना सरणी को स्लाइड करने वाले पॉइंटर को बढ़ाता है।

यहां सी में एक उदाहरण दिया गया है:

char hello[] = "hello";

char *p = hello;

while (*p)
{
    *p += 1; // increase the character by one

    p += 1; // move to the next spot
}

printf(hello);

प्रिंट

ifmmp

क्योंकि यह प्रत्येक चरित्र के लिए मूल्य लेता है और इसे एक से बढ़ाता है।

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

असल में मेरे पास तीन प्रश्न हैं:

  1. सामान्य चर पर पॉइंटर्स का उपयोग क्यों करें?
  2. मुझे पॉइंटर्स का कब और कहाँ उपयोग करना चाहिए?
  3. आप सरणी के साथ पॉइंटर्स का उपयोग कैसे करते हैं?

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

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

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

सी ++ में पॉइंटर्स का उपयोग करने का एक और अच्छा कारण पुस्तकालयों से फिर से संबंधित है, एक ऐसा डीएल होने पर विचार करें जो आपके प्रोग्राम के दौरान लोड नहीं किया जा सकता है, इसलिए यदि आप एक आयात लाइब्रेरी का उपयोग करते हैं तो निर्भरता संतुष्ट नहीं होती है और प्रोग्राम क्रैश हो जाता है। उदाहरण के लिए यह मामला है जब आप अपने आवेदन के साथ एक डीएल में एक सार्वजनिक एपीआई देते हैं और आप इसे अन्य अनुप्रयोगों से एक्सेस करना चाहते हैं। इस मामले में एपीआई का उपयोग करने के लिए आपको अपने 'स्थान (आमतौर पर यह एक रजिस्ट्री कुंजी में) से डीएल लोड करने की आवश्यकता होती है और फिर आपको DLL के अंदर फ़ंक्शन कॉल करने में सक्षम होने के लिए फ़ंक्शन पॉइंटर का उपयोग करने की आवश्यकता होती है। कभी-कभी एपीआई बनाने वाले लोग आपको एक .h फ़ाइल देने के लिए काफी अच्छे होते हैं जिसमें इस प्रक्रिया को स्वचालित करने के लिए सहायक फ़ंक्शन होते हैं और आपको आवश्यक सभी फ़ंक्शन पॉइंटर्स देते हैं, लेकिन यदि आप लोड लाइब्रेरी और GetProcAddress को Windows और dlopen पर उपयोग नहीं कर सकते हैं और उन्हें प्राप्त करने के लिए यूनिक्स पर dlsym (इस पर विचार करें कि आप समारोह के पूरे हस्ताक्षर जानते हैं)।


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


जावा और सी # में सभी ऑब्जेक्ट संदर्भ पॉइंटर्स हैं, सी ++ के साथ यह बात यह है कि आप पॉइंटर पॉइंट्स पर अधिक नियंत्रण रखते हैं। याद रखें महान शक्ति के साथ भव्य जिम्मेदारी आता है।


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

पॉइंटर्स उपयोगी होते हैं जहां आपको उच्च प्रदर्शन और / या कॉम्पैक्ट मेमोरी पदचिह्न की आवश्यकता होती है।

आपके सरणी में पहले तत्व का पता एक सूचक को असाइन किया जा सकता है। यह आपको सीधे अंतर्निहित आवंटित बाइट्स तक पहुंचने की अनुमति देता है। किसी सरणी का पूरा बिंदु आपको ऐसा करने की आवश्यकता से बचने के लिए है।


पॉइंटर्स का उपयोग करने का एक कारण यह है कि किसी चर या फ़ंक्शन को किसी फ़ंक्शन में संशोधित किया जा सकता है।

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

निम्नलिखित उदाहरणों पर विचार करें:

संदर्भों का उपयोग करना:

public void doSomething()
{
    int i = 10;
    doSomethingElse(i);  // passes i by references since doSomethingElse() receives it
                         // by reference, but the syntax makes it appear as if i is passed
                         // by value
}

public void doSomethingElse(int& i)  // receives i as a reference
{
    cout << i << endl;
}

पॉइंटर्स का उपयोग करना:

public void doSomething()
{
    int i = 10;
    doSomethingElse(&i);
}

public void doSomethingElse(int* i)
{
    cout << *i << endl;
}

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

डॉस के पुराने दिनों में, आप सीधे पॉइंटर घोषित करके वीडियो कार्ड की वीडियो मेमोरी तक पहुंचने में सक्षम होते थे:

unsigned char *pVideoMemory = (unsigned char *)0xA0000000;

कई एम्बेडेड डिवाइस अभी भी इस तकनीक का उपयोग करते हैं।


बड़े हिस्से में, पॉइंटर्स एरे होते हैं (सी / सी ++ में) - वे मेमोरी में पते होते हैं, और वांछित होने पर सरणी की तरह एक्सेस किया जा सकता है ("सामान्य" मामलों में)।

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

यदि आप गतिशील संग्रहण आवंटन करना चाहते हैं (जैसे कि एक लिंक्ड-लिस्ट के लिए), तो आपको पॉइंटर्स का उपयोग करना होगा, क्योंकि वे ढेर से स्मृति को पकड़ने का एकमात्र तरीका हैं।


यहां थोड़ा अलग है, लेकिन अंतर्दृष्टि लेते हैं कि सी की कई विशेषताएं क्यों समझती हैं: http://steve.yegge.googlepages.com/tour-de-babel#C

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

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


यहां मेरा एन्वेयर है, और मैं एक विशेषज्ञ होने का वादा नहीं करूंगा, लेकिन मुझे अपने पुस्तकालयों में से एक में पॉइंटर्स बहुत अच्छा लगता है, जिसे मैं लिखने की कोशिश कर रहा हूं। इस लाइब्रेरी में (यह ओपनजीएल :-) के साथ एक ग्राफिक्स एपीआई है) आप उनमें से गुजरने वाली वर्टेक्स ऑब्जेक्ट्स के साथ त्रिकोण बना सकते हैं। ड्रॉ विधि इन त्रिकोण वस्तुओं को लेती है, और अच्छी तरह से .. उन्हें बनाए गए कशेरुक वस्तुओं के आधार पर खींचती है। खैर यह ठीक है।

लेकिन, अगर मैं वर्टेक्स समन्वय बदलता हूं तो क्या होगा? चरम वर्ग में moveX () के साथ इसे या कुछ ले जाएं? खैर, ठीक है, अब मुझे त्रिकोण को अद्यतन करना है, और अधिक विधियों को जोड़ना और प्रदर्शन बर्बाद हो रहा है क्योंकि मुझे हर बार एक चरम चाल को त्रिकोण अद्यतन करना होता है। अभी भी एक बड़ा सौदा नहीं है, लेकिन यह इतना अच्छा नहीं है।

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

पॉइंटर्स के साथ, आपको त्रिकोण को अपडेट करने की आवश्यकता नहीं है।

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


सी भाषा में पॉइंटर्स की आवश्यकता here वर्णित here

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

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

पीएस: कृपया नमूना कोड के साथ विस्तृत स्पष्टीकरण के लिए here देखें।


  • कुछ मामलों में, फ़ंक्शन पॉइंटर्स को साझा लाइब्रेरी (डीएलएल या .so) में मौजूद फ़ंक्शंस का उपयोग करने की आवश्यकता होती है। इसमें भाषाओं भर में सामान शामिल करना शामिल है, जहां कई बार एक डीएलएल इंटरफ़ेस प्रदान किया जाता है।
  • कंपाइलर बनाना
  • वैज्ञानिक कैलकुलेटर बनाना, जहां आपके पास फ़ंक्शन पॉइंटर्स का सरणी या वेक्टर या स्ट्रिंग मैप है?
  • वीडियो मेमोरी को सीधे संशोधित करने की कोशिश कर रहा है - अपना खुद का ग्राफिक्स पैकेज बनाना
  • एक एपीआई बनाना!
  • डेटा संरचनाएं - विशेष पेड़ के लिए नोड लिंक पॉइंटर्स जो आप बना रहे हैं

पॉइंटर्स के लिए कई कारण हैं। यदि आप क्रॉस-भाषा संगतता को बनाए रखना चाहते हैं तो डीएलएल में विशेष रूप से महत्वपूर्ण है।






pointers