बाकी कई भाषाओं की तरह C++ में भी पॉइंटर होते हैं। आप जानते हैं कि रेफरेंस और पॉइंटर काफी मिलते-जुलते हैं, लेकिन इन्हें अपने कंप्यूटर के अंदरूनी कामकाज के एक कदम और करीब समझिए। पॉइंटर ऐसे वेरिएबल होते हैं जिनमें ऑब्जेक्ट के एड्रेस रखे जाते हैं। इन्हीं की मदद से ऑब्जेक्ट के साथ सीधे काम किया जाता है, जिससे C++ में डायनामिक मेमोरी आवंटन और डेटा को कुशलता से संभालना मुमकिन होता है।
अगर आप पॉइंटर के लिए नए हैं, तो ये थोड़े रहस्यमय लग सकते हैं, लेकिन जैसे ही आप इनके आदी हो जाते हैं, ये काफी आसान लगने लगते हैं।
ये C++ का बहुत ज़रूरी हिस्सा हैं, इसलिए इन्हें अच्छी तरह समझने के लिए कुछ समय ज़रूर दीजिए। इस कॉन्सेप्ट में जो बुनियादी रूप आप देखेंगे, उसे डंब पॉइंटर या रॉ पॉइंटर भी कहते हैं। आधुनिक C++ में स्मार्ट पॉइंटर भी होते हैं। बुनियादी पॉइंटर बिलकुल भी स्मार्ट नहीं होते, उनका सारा काम आपको खुद संभालना पड़ता है।
बारीकियों में उतरने से पहले यह समझ लेना फायदेमंद रहेगा कि पॉइंटर किस काम आते हैं। इनकी मदद से हम किसी ऑब्जेक्ट का एड्रेस अपने प्रोग्राम के दूसरे हिस्सों के साथ साझा कर सकते हैं, और यह दो बड़े कारणों से काम का है:
C++ में पॉइंटर घोषित करने के लिए आपको वह डेटा टाइप बताना होता है जिसकी ओर पॉइंटर इशारा करेगा, उसके बाद एक तारा (*) और पॉइंटर का नाम लिखना होता है।
पॉइंटर घोषित करते समय उन्हें अपने आप कोई शुरुआती वैल्यू नहीं मिलती।
बिना साफ-साफ वैल्यू असाइन किए आम तौर पर पॉइंटर के अंदर कोई अनिश्चित वैल्यू रहती है, जिसे अक्सर "कचरा एड्रेस" कहा जाता है।
कुछ कंपाइलर पॉइंटर को शुरू में ही nullptr बना देते हैं, लेकिन हर कंपाइलर ऐसा करेगा, इसकी कोई गारंटी नहीं है, इसलिए इस पर भरोसा करना ठीक नहीं है।
इसलिए यह अच्छा तरीका है कि रॉ पॉइंटर को साफ-साफ शुरुआती वैल्यू दीजिए और इस्तेमाल से पहले जाँच लीजिए कि उसमें null नहीं है, ताकि आगे कोई दिक्कत न आए।
int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid
किसी वेरिएबल का एड्रेस किसी पॉइंटर को असाइन करने के लिए आप एड्रेस-ऑफ ऑपरेटर (&) इस्तेमाल करते हैं।
किसी पॉइंटर को डीरेफरेंस करने के लिए इनडायरेक्शन ऑपरेटर (*) का उपयोग किया जाता है।
std::string opponent{"Solomon Lane"};
// 'ethan' points to the address of the string opponent
std::string* ethan{&opponent};
// Instead of ethan's, the opponent's name address is given to the passPort
std::string passportName{*ethan};
ध्यान दीजिए: डीरेफरेंसिंग साफ-साफ करनी पड़ती है, जबकि रेफरेंस उपनाम की तरह अपने आप काम करते रहते हैं।
पॉइंटर अर्थमेटिक की मदद से आप पॉइंटर पर गणितीय काम कर सकते हैं, जो ऐरे के साथ काम करते समय खास तौर पर काम आता है। किसी पॉइंटर में कोई पूर्णांक जोड़ने पर वह किसी दूसरे एलिमेंट की ओर इशारा करने लगता है।
// Stargate Coordinate Code
int gateCode[] = {462, 753, 218, 611, 977};
// 'ptr' points to the first element of 'gateCode'
int* ptr{&gateCode[0]};
// Accesses the third Stargate address through pointer arithmetic
int dialedAddress{*(ptr + 2)};
// Chevron encoded! Dialing Stargate address:
openStarGate(dialedAddress);
C++ में पॉइंटर अर्थमेटिक को संभालते समय ज़रा भी लापरवाही बरती जाए, तो यह आसानी से अपरिभाषित व्यवहार तक पहुँच सकता है। अपरिभाषित व्यवहार अप्रत्याशित नतीजों, क्रैश, या सुरक्षा से जुड़ी कमजोरियों के रूप में सामने आ सकता है। अपरिभाषित व्यवहार के नतीजों का एक कुख्यात उदाहरण 1996 में एरियन 5 रॉकेट के विस्फोट के रूप में सामने आया था, जहाँ 64-बिट दशमलव संख्या को 16-बिट साइन्ड पूर्णांक में बदलने से पैदा हुए सॉफ्टवेयर एक्सेप्शन ने एक भयानक विफलता को जन्म दिया।
C++ में -> ऑपरेटर की मदद से आप किसी ऑब्जेक्ट के पॉइंटर के ज़रिए उसके मेंबर एक्सेस कर सकते हैं।
यह एक छोटा रूप है, जो पॉइंटर से इशारा किए गए ऑब्जेक्ट के मेंबर एक्सेस करना आसान बना देता है।
उदाहरण के लिए, अगर ptr किसी ऐसे ऑब्जेक्ट का पॉइंटर है जिसमें x नाम का मेंबर वेरिएबल है, तो (*ptr).x लिखने के बजाय आप सीधे ptr->x लिख सकते हैं।
ऑब्जेक्ट के पॉइंटर के साथ काम करते समय यह ऑपरेटर कोड को पढ़ने में आसान बनाता है और कोड को कम लंबा-चौड़ा बनाता है।
यहाँ एक छोटा उदाहरण देखिए, जिसमें Superhero नाम का एक struct है और उसमें superpower नाम का मेंबर वेरिएबल है।
main फंक्शन Superhero ऑब्जेक्ट (जो Wonder Woman को दर्शाता है) का एक पॉइंटर dianaPrince बनाता है।
-> ऑपरेटर का उपयोग superpower मेंबर वेरिएबल को एक्सेस करने के लिए किया गया है, जो Wonder Woman की मशहूर "Lasso of Truth" दिखाता है।
struct Superhero {
std::string superpower;
};
Superhero wonder_woman{};
Superhero* dianaPrince = &wonder_woman;
dianaPrince->superpower = "Lasso of Truth";
// Using the -> operator to access member variable superpower:
std::cout << "Wonder Woman, possesses the mighty " << dianaPrince->superpower;
पॉइंटर और रेफरेंस, दोनों ही ऑब्जेक्ट तक अप्रत्यक्ष रूप से पहुँचने देते हैं, लेकिन अपनी क्षमताओं और सुरक्षा के मामले में दोनों अलग हैं। पॉइंटर अपना लक्ष्य ऑब्जेक्ट बदलने की सुविधा देते हैं और इन्हें null भी असाइन किया जा सकता है। लेकिन यही सुविधा कुछ जोखिम भी लाती है, जैसे null पॉइंटर को डीरेफरेंस करना या डैंगलिंग पॉइंटर बना देना। दूसरी ओर, रेफरेंस null नहीं हो सकते और बनते ही किसी मान्य ऑब्जेक्ट से जुड़ जाते हैं, जिससे ये जोखिम टल जाते हैं। चूँकि रेफरेंस ज़्यादा सुरक्षित होते हैं, इसलिए जब तक पॉइंटर की अतिरिक्त सुविधाएँ सचमुच ज़रूरी न हों, रेफरेंस को ही प्राथमिकता देनी चाहिए।
स्वागत है, इंजीनियर! आप Speedywagon Foundation के उन गिने-चुने दिग्गजों में से हैं जो अब तक बचे हैं। यह एक गुप्त संस्था है, जो दशकों से Pillar Men जैसे पुराने खतरों से लोहा लेती आ रही है। इस काम के दौरान आपने कई साल Speedywagon Foundation के तकनीकी सिस्टम की देखरेख करने में लगाए हैं, जो नई तकनीक और पुरानी लाइब्रेरी के मेल से बने हैं।
लेकिन इन दिनों Pillar Men की गतिविधियों पर नज़र रखने वाले सेंसर ठीक से काम नहीं कर रहे हैं। Speedywagon Foundation के सिस्टम पुराने हैं, और यह कोड एक पुरानी C++ लाइब्रेरी से जुड़ा है जिसे अपडेट नहीं किया जा सकता। आपको चार मुख्य फंक्शन बनाने हैं, जो पुराने ज़माने की पॉइंटर-आधारित लाइब्रेरी की मदद से Pillar Men सेंसर की गतिविधि पर नज़र रखते हैं।
आधुनिक C++ इंजीनियर होने के नाते आप स्मार्ट पॉइंटर इस्तेमाल करना पसंद करेंगे, लेकिन पुराने कोड को पुराने तरीकों का सम्मान देना ही पड़ता है। मानवता का भविष्य इन पॉइंटरों पर टिका हो सकता है, इसलिए सावधानी से आगे बढ़िए, और Hamon ऊर्जा आपका मार्गदर्शन करे।
चूँकि सेंसर की रीडिंग बहुत बड़ी हो सकती है, इसलिए हम एक नमूना struct दे रहे हैं, जो असली लाइब्रेरी में इस्तेमाल होता है। यह कोड आपके लिए हेडर फाइल में पहले से बना दिया गया है।
struct pillar_men_sensor {
int activity{};
std::string location{};
std::vector<int> data{};
};
connection_check)सबसे पहले आपको यह देखना है कि Pillar Men सेंसर ठीक से जुड़ा है या नहीं।
सेंसर के जुड़े न होने पर झूठे अलार्म नहीं बजने चाहिए।
आप एक फंक्शन connection_check लिखेंगे, जो nullptr जाँचकर बताता है कि सेंसर का पॉइंटर मान्य है या नहीं।
pillar_men_sensor struct के पॉइंटर को लेता हो।true लौटाए, वरना false।pillar_men_sensor* sensor{nullptr};
bool isConnected = connection_check(sensor);
// isConnected => false
activity_counter)Pillar Men छाया में छिपे हुए हैं, और हमें पता होना चाहिए कि सेंसरों ने कोई गतिविधि पकड़ी है या नहीं।
आप activity_counter फंक्शन लिखेंगे, जो सेंसरों का एक ऐरे और ऐरे में मौजूद सेंसरों की संख्या बताने वाली क्षमता लेता है।
pillar_men_sensor sensor_array[3] = {{0}, {101}, {22}};
int totalActivity = activity_counter(sensor_array, 3);
// totalActivity => 123
alarm_control)हर सेंसर से अलार्म नहीं बजना चाहिए; अलार्म तभी बजना चाहिए जब वाकई कोई खतरा हो।
alarm_control फंक्शन यह सुनिश्चित करता है कि सेंसर अलार्म तभी बजाए जब उसकी गतिविधि का स्तर 0 से ज़्यादा हो।
यह फंक्शन null सेंसर भी जाँचता है, ताकि सिस्टम क्रैश न हो।
pillar_men_sensor का पॉइंटर लेता हो।nullptr है या नहीं। अगर सेंसर nullptr है तो false लौटाइए।true लौटाइए, वरना false।pillar_men_sensor db{9008, "songokunoie", {7, 7, 7}};
bool alarm = alarm_control(&db);
// alarm => true
uv_alarm फंक्शन से डेटा में असामान्यताएँ जाँचिएइस काम में आप uv_alarm फंक्शन बनाएँगे, जो यह तय करता है कि UV रोशनी के स्तर और सेंसर की गतिविधि के आधार पर अलार्म बजाना चाहिए या नहीं।
uv_alarm फंक्शन को दिए गए uv_light_heuristic फंक्शन का इस्तेमाल करना चाहिए, जो डेटा के वेक्टर पर काम करता है और कुछ सीमाओं के आधार पर एक वैल्यू लौटाता है।
यह उस जटिल कोड का नमूना रूप है जो असल में चलेगा, इसलिए कृपया इसका इंटरफेस न बदलिए।
uv_alarm फंक्शन को speedywagon नेमस्पेस में बनाइए। इस फंक्शन को यह करना है:
pillar_men_sensor struct का पॉइंटर लेना।false लौटाना।data ऐरे का पता देकर uv_light_heuristic फंक्शन को कॉल करना।uv_light_heuristic से लौटी वैल्यू sensor->activity के स्तर से ज़्यादा है तो true लौटाना, वरना false।Exercism पर साइन अप कीजिए और C++ को 19 कॉन्सेप्ट100 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।