कृपया स्पष्टीकरण के साथ एक उदाहरण शामिल करें।
int *p;
एक पॉइंटर को एक पूर्णांक के लिए परिभाषित करेगा, और *p
उस पॉइंटर को डिरेल करेगा, जिसका अर्थ है कि यह वास्तव में उस डेटा को पुनः प्राप्त करेगा जो पी को इंगित करता है।
कृपया स्पष्टीकरण के साथ एक उदाहरण शामिल करें।
int *p;
एक पॉइंटर को एक पूर्णांक के लिए परिभाषित करेगा, और *p
उस पॉइंटर को डिरेल करेगा, जिसका अर्थ है कि यह वास्तव में उस डेटा को पुनः प्राप्त करेगा जो पी को इंगित करता है।
जवाबों:
यह आम तौर पर पर्याप्त अच्छा है - जब तक आप असेंबली प्रोग्रामिंग नहीं कर रहे हैं - एक संख्यात्मक स्मृति पते वाले एक पॉइंटर की परिकल्पना करने के लिए, प्रक्रिया की मेमोरी में दूसरे बाइट का संदर्भ देते हुए, 2 तीसरे, 3 चौथे और इतने पर ...।
जब आप उस मेमोरी में डेटा / मूल्य को एक्सेस करना चाहते हैं जो पॉइंटर इंगित करता है - उस संख्यात्मक सूचकांक के साथ पते की सामग्री - तब आप डीरेफेरेंस करते हैं पॉइंटर को करते हैं।
विभिन्न कंप्यूटर भाषाओं में संकलक या दुभाषिया को यह बताने के लिए अलग-अलग संकेतन हैं कि अब आप पॉइंट-इन ऑब्जेक्ट (वर्तमान) मान में रुचि रखते हैं - मैं नीचे C और C ++ पर ध्यान केंद्रित करता हूं।
सी में विचार करें, p
नीचे दिए गए जैसे एक संकेतक ...
const char* p = "abc";
... संख्यात्मक डेटा के साथ चार बाइट्स अक्षर 'एन', 'बी', 'सी', और टेक्स्ट डेटा के अंत को दर्शाने के लिए एक 0 बाइट को सांकेतिक शब्दों में बदलना करने के लिए उपयोग किया जाता है, स्मृति और उस के संख्यात्मक पते में कहीं संग्रहीत होते हैं में डेटा संग्रहीत है p
। इस तरह सी मेमोरी में टेक्स्ट को ASCIIZ के रूप में जाना जाता है ।
उदाहरण के लिए, यदि स्ट्रिंग शाब्दिक पते 0x1000 और p
0x2000 पर 32-बिट सूचक है, तो मेमोरी सामग्री निम्न होगी:
Memory Address (hex) Variable name Contents
1000 'a' == 97 (ASCII)
1001 'b' == 98
1002 'c' == 99
1003 0
...
2000-2003 p 1000 hex
ध्यान दें कि पता 0x1000 के लिए कोई चर नाम / पहचानकर्ता नहीं है, लेकिन हम अप्रत्यक्ष रूप से स्ट्रिंग पॉरल को इंगित कर सकते हैं, जो इसके पते को संचयित करता है p
।
वर्ण p
बिंदुओं को संदर्भित करने के लिए, हम p
इनमें से एक संकेतन (फिर से, C के लिए) का उपयोग करके हस्तक्षेप करते हैं:
assert(*p == 'a'); // The first character at address p will be 'a'
assert(p[1] == 'b'); // p[1] actually dereferences a pointer created by adding
// p and 1 times the size of the things to which p points:
// In this case they're char which are 1 byte in C...
assert(*(p + 1) == 'b'); // Another notation for p[1]
आप इंगित किए गए डेटा के माध्यम से भी पॉइंटर्स को स्थानांतरित कर सकते हैं, जैसे ही आप जाते हैं, उन्हें डीफ़र करना:
++p; // Increment p so it's now 0x1001
assert(*p == 'b'); // p == 0x1001 which is where the 'b' is...
यदि आपके पास कुछ डेटा है जिसे लिखा जा सकता है, तो आप इस तरह की चीजें कर सकते हैं:
int x = 2;
int* p_x = &x; // Put the address of the x variable into the pointer p_x
*p_x = 4; // Change the memory at the address in p_x to be 4
assert(x == 4); // Check x is now 4
ऊपर, आप संकलन समय पर जानते होंगे कि आपको एक चर नाम की आवश्यकता होगी x
, और कोड संकलक को यह व्यवस्था करने के लिए कहता है कि इसे कहाँ संग्रहीत किया जाना चाहिए, यह सुनिश्चित करते हुए पता उपलब्ध होगा&x
।
C में, यदि आपके पास एक चर है जो डेटा सदस्यों के साथ एक संरचना के लिए एक संकेतक है, तो आप उन सदस्यों तक पहुँच प्राप्त कर सकते हैं जो ->
डीरेकालाइंसिंग का उपयोग कर रहे हैं :
typedef struct X { int i_; double d_; } X;
X x;
X* p = &x;
p->d_ = 3.14159; // Dereference and access data member x.d_
(*p).d_ *= -1; // Another equivalent notation for accessing x.d_
एक पॉइंटर का उपयोग करने के लिए, कंप्यूटर प्रोग्राम को उस डेटा के प्रकार में कुछ अंतर्दृष्टि की आवश्यकता होती है, जिस पर इंगित किया जा रहा है - यदि उस डेटा प्रकार को प्रतिनिधित्व करने के लिए एक से अधिक बाइट की आवश्यकता होती है, तो पॉइंटर सामान्य रूप से डेटा में सबसे कम संख्या वाले बाइट को इंगित करता है।
तो, थोड़ा और जटिल उदाहरण देख रहे हैं:
double sizes[] = { 10.3, 13.4, 11.2, 19.4 };
double* p = sizes;
assert(p[0] == 10.3); // Knows to look at all the bytes in the first double value
assert(p[1] == 13.4); // Actually looks at bytes from address p + 1 * sizeof(double)
// (sizeof(double) is almost always eight bytes)
++p; // Advance p by sizeof(double)
assert(*p == 13.4); // The double at memory beginning at address p has value 13.4
*(p + 2) = 29.8; // Change sizes[3] from 19.4 to 29.8
// Note earlier ++p and + 2 here => sizes[3]
कभी-कभी आपको नहीं पता होता है कि आपके प्रोग्राम के चलने तक आपको कितनी मेमोरी की आवश्यकता होगी और देखता है कि उस पर कौन सा डेटा फेंका गया है ... तो आप डायनामिक रूप से मेमोरी का उपयोग करके आवंटित कर सकते हैं malloc
। यह एक सूचक में पते को संग्रहीत करने के लिए आम बात है ...
int* p = (int*)malloc(sizeof(int)); // Get some memory somewhere...
*p = 10; // Dereference the pointer to the memory, then write a value in
fn(*p); // Call a function, passing it the value at address p
(*p) += 3; // Change the value, adding 3 to it
free(p); // Release the memory back to the heap allocation library
C ++ में, मेमोरी आवंटन आम तौर पर new
ऑपरेटर के साथ किया जाता है , और इसके साथ सौदा delete
:
int* p = new int(10); // Memory for one int with initial value 10
delete p;
p = new int[10]; // Memory for ten ints with unspecified initial value
delete[] p;
p = new int[10](); // Memory for ten ints that are value initialised (to 0)
delete[] p;
C ++ स्मार्ट पॉइंटर्स भी देखेंनीचे ।
अक्सर एक संकेतक एकमात्र संकेत हो सकता है जहां कुछ डेटा या बफर स्मृति में मौजूद हैं। यदि उस डेटा / बफर के चल रहे उपयोग की आवश्यकता है, या कॉल करने की क्षमता है free()
या delete
मेमोरी लीक करने से बचने के लिए, तो प्रोग्रामर को पॉइंटर की एक कॉपी पर काम करना होगा ...
const char* p = asprintf("name: %s", name); // Common but non-Standard printf-on-heap
// Replace non-printable characters with underscores....
for (const char* q = p; *q; ++q)
if (!isprint(*q))
*q = '_';
printf("%s\n", p); // Only q was modified
free(p);
... या ध्यान से किसी भी परिवर्तन के ऑर्केस्ट्रेट उत्क्रमण ...
const size_t n = ...;
p += n;
...
p -= n; // Restore earlier value...
free(p);
C ++ में, स्मार्ट पॉइंटर ऑब्जेक्ट्स को स्टोर करने और पॉइंटर्स को प्रबंधित करने के लिए स्मार्ट पॉइंटर ऑब्जेक्ट्स का उपयोग करना सबसे अच्छा अभ्यास है , स्मार्ट पॉइंटर्स के डिस्ट्रक्टर्स चलने पर स्वचालित रूप से उन्हें डीलिट करते हैं। C ++ 11 के बाद से मानक पुस्तकालय दो प्रदान करता है, unique_ptr
जब एक आवंटित वस्तु के लिए एक ही मालिक होता है ...
{
std::unique_ptr<T> p{new T(42, "meaning")};
call_a_function(p);
// The function above might throw, so delete here is unreliable, but...
} // p's destructor's guaranteed to run "here", calling delete
... और shared_ptr
शेयर स्वामित्व ( संदर्भ गणना का उपयोग करके ) ...
{
auto p = std::make_shared<T>(3.14, "pi");
number_storage1.may_add(p); // Might copy p into its container
number_storage2.may_add(p); // Might copy p into its container } // p's destructor will only delete the T if neither may_add copied it
C में, NULL
और 0
- और इसके अलावा C ++ में nullptr
- यह इंगित करने के लिए उपयोग किया जा सकता है कि एक पॉइंटर वर्तमान में एक चर का मेमोरी पता नहीं रखता है, और इसे पॉरिथ्रिम अंकगणित में उपयोग या उपयोग नहीं किया जाना चाहिए। उदाहरण के लिए:
const char* p_filename = NULL; // Or "= 0", or "= nullptr" in C++
int c;
while ((c = getopt(argc, argv, "f:")) != -1)
switch (c) {
case f: p_filename = optarg; break;
}
if (p_filename) // Only NULL converts to false
... // Only get here if -f flag specified
सी और सी ++ में, इनबिल्ट सांख्यिक प्रकार जरूरी के लिए डिफ़ॉल्ट नहीं है बस के रूप में 0
, और न ही bools
करने के लिए false
, संकेत हमेशा के लिए सेट नहीं कर रहे हैंNULL
। इन सभी 0 / गलत / शून्य पर सेट कर रहे हैं जब वे static
चर या (सी ++ केवल) प्रत्यक्ष या अप्रत्यक्ष स्थिर वस्तुओं के सदस्य चर या उनके ठिकानों, या शून्य initialisation (जैसे गुजरना new T();
और new T(x, y, z);
संकेत सहित टी के सदस्यों पर शून्य initialisation करते हैं, जबकि new T;
नहीं करता)।
इसके अलावा, जब आप असाइन करते हैं 0
, NULL
औरnullptr
एक पॉइंटर को पॉइंटर में बिट्स सभी रीसेट नहीं होते हैं: पॉइंटर में हार्डवेयर स्तर पर "0" नहीं हो सकता है, या आपके वर्चुअल एड्रेस स्पेस में एड्रेस 0 को संदर्भित कर सकता है। संकलक किसी और वहाँ अगर यह करने के लिए कारण है की दुकान में कुछ करने की अनुमति दी है, लेकिन जो कुछ भी यह होता है - आप के साथ आते हैं और करने के लिए सूचक की तुलना 0
, NULL
,nullptr
या किसी अन्य सूचक है कि उन में से किसी सौंपा गया था, के रूप में उम्मीद की तुलना करना चाहिए काम करते हैं। इसलिए, संकलक स्तर पर स्रोत कोड के नीचे, "NULL" संभवतः C और C ++ भाषाओं में थोड़ा "जादुई" है ...
अधिक सख्ती से, प्रारंभिक बिंदु एक बिट-पैटर्न की पहचान करते हैं जो NULL
या तो (अक्सर) आभासी ) मेमोरी एड्रेस को ।
साधारण मामला यह है कि यह प्रक्रिया के संपूर्ण आभासी पता स्थान में एक संख्यात्मक ऑफसेट है; अधिक जटिल मामलों में सूचक कुछ विशिष्ट मेमोरी क्षेत्र के सापेक्ष हो सकता है, जो सीपीयू "सेगमेंट" रजिस्टरों के आधार पर चयन कर सकता है या बिट-पैटर्न में एन्कोड किए गए सेगमेंट आईडी के कुछ तरीके, और / या विभिन्न स्थानों पर निर्भर करता है। पता का उपयोग करते हुए मशीन कोड निर्देश।
उदाहरण के लिए, वैरिएबल int*
को इंगित करने के लिए ठीक से आरंभ किया जा int
सकता है - float*
"जीपीयू" मेमोरी में एक्सेस मेमोरी के लिए कास्टिंग करने के बाद , यह मेमोरी से काफी अलग होता int
है, जहां वैरिएबल है, फिर एक बार एक फंक्शन पॉइंटर के रूप में कास्ट और इस्तेमाल किया जा सकता है। कार्यक्रम के लिए अलग मेमोरी होल्डिंग मशीन ऑपकोड ( int*
प्रभावी रूप से इन अन्य मेमोरी क्षेत्रों के भीतर एक यादृच्छिक, अमान्य सूचक का संख्यात्मक मान के साथ )।
C और C ++ जैसी 3GL प्रोग्रामिंग लैंग्वेज इस जटिलता को छिपाने का काम करती हैं, जैसे:
यदि कंपाइलर आपको एक चर या फ़ंक्शन के लिए एक पॉइंटर देता है, तो आप इसे स्वतंत्र रूप से (जब तक कि वैरिएबल डिस्ट्रक्टेड / डीललॉकेटेड नहीं होता है) को स्वतंत्र रूप से डिफाइन कर सकते हैं और यह कंपाइलर की समस्या है कि क्या किसी विशेष सीपीयू सेगमेंट रजिस्टर को पहले से बहाल करने की आवश्यकता है, या ए अलग मशीन कोड निर्देश का इस्तेमाल किया
यदि आपको किसी सरणी में एक तत्व के लिए एक संकेतक मिलता है, तो आप सरणी में कहीं और स्थानांतरित करने के लिए सूचक अंकगणितीय का उपयोग कर सकते हैं, या यहां तक कि किसी अन्य बिंदुओं के साथ तुलना करने के लिए कानूनी सरणी के एक-एक-छोर का पता बनाने के लिए भी उपयोग कर सकते हैं। सरणी में (या जो समान रूप से सूचक अंकगणितीय द्वारा समान एक-अतीत-के-अंत मूल्य पर ले जाया गया है); C और C ++ में फिर से, यह "बस काम करता है" यह सुनिश्चित करने के लिए कंपाइलर पर निर्भर है
विशिष्ट OS फ़ंक्शंस, उदाहरण के लिए साझा की गई मेमोरी मैपिंग, आपको संकेत दे सकती है, और वे उन पते की सीमा के भीतर "बस काम" करेंगे जो उनके लिए समझ में आते हैं
इन सीमाओं से परे कानूनी बिंदुओं को स्थानांतरित करने के लिए, या मनमाने ढंग से संख्याओं को इंगित करने के लिए या असंबंधित प्रकारों के लिए उपयोग किए गए पॉइंटर्स का उपयोग करने का प्रयास करना, आमतौर पर अपरिभाषित व्यवहार होता है , इसलिए उच्च स्तर के पुस्तकालयों और अनुप्रयोगों में टाला जाना चाहिए, लेकिन ओएसिस, डिवाइस ड्राइवर, आदि के लिए कोड। सी या सी ++ मानक द्वारा अपरिभाषित छोड़ दिए गए व्यवहार पर भरोसा करने की आवश्यकता हो सकती है, फिर भी उनके विशिष्ट कार्यान्वयन या हार्डवेयर द्वारा अच्छी तरह से परिभाषित किया गया है।
p[1]
और *(p + 1)
समान ? यही कारण है, करता है p[1]
और *(p + 1)
एक ही निर्देश प्राप्त होती है?
p
सिर्फ 2000 है: यदि आपके पास एक और पॉइंटर था, तो p
उसे अपने चार या आठ बाइट्स में 2000 स्टोर करना होगा। उम्मीद है की वो मदद करदे! चीयर्स।
u
में एक सरणी होती है arr
, तो जीसीसी और क्लैंग दोनों यह पहचान लेंगे कि लैवल्यू u.arr[i]
अन्य यूनियन सदस्यों के समान ही स्टोरेज एक्सेस कर सकता है, लेकिन यह नहीं पहचानेगा कि लैवेल्यू *(u.arr+i)
ऐसा कर सकता है। मुझे यकीन नहीं है कि क्या उन संकलक के लेखकों को लगता है कि उत्तरार्द्ध यूबी को आमंत्रित करता है, या कि पूर्व यूबी को आमंत्रित करता है, लेकिन उन्हें इसे वैसे भी उपयोगी तरीके से संसाधित करना चाहिए, लेकिन वे स्पष्ट रूप से दो अभिव्यक्तियों को अलग-अलग मानते हैं।
एक पॉइंटर को डीफ्रेंसिंग करने का अर्थ है कि पॉइंटर द्वारा बताए गए मेमोरी लोकेशन में स्टोर किया गया मान। इसे करने के लिए ऑपरेटर * का उपयोग किया जाता है, और इसे dereferencing ऑपरेटर कहा जाता है।
int a = 10;
int* ptr = &a;
printf("%d", *ptr); // With *ptr I'm dereferencing the pointer.
// Which means, I am asking the value pointed at by the pointer.
// ptr is pointing to the location in memory of the variable a.
// In a's location, we have 10. So, dereferencing gives this value.
// Since we have indirect control over a's location, we can modify its content using the pointer. This is an indirect way to access a.
*ptr = 20; // Now a's content is no longer 10, and has been modified to 20.
[]
भी एक पॉइंटर को इंगित करता है ( a[b]
इसका अर्थ है परिभाषित *(a + b)
)।
एक पॉइंटर एक मान के लिए "संदर्भ" है .. एक पुस्तकालय कॉल नंबर की तरह एक किताब के लिए एक संदर्भ है। "डेरेफ्रेंसिंग" कॉल नंबर शारीरिक रूप से उस किताब से गुजर रहा है और उसे पुनर्प्राप्त कर रहा है।
int a=4 ;
int *pA = &a ;
printf( "The REFERENCE/call number for the variable `a` is %p\n", pA ) ;
// The * causes pA to DEREFERENCE... `a` via "callnumber" `pA`.
printf( "%d\n", *pA ) ; // prints 4..
यदि पुस्तक नहीं है, तो लाइब्रेरियन चिल्लाना शुरू कर देता है, लाइब्रेरी को बंद कर देता है, और एक ऐसे व्यक्ति के कारण की जांच करने के लिए सेट किया जाता है जो पुस्तक नहीं है।
कोड और पॉइंटर मूल बातें से स्पष्टीकरण :
डीपरेशन ऑपरेशन पॉइंटर पर शुरू होता है और इसके पॉइंटर तक पहुंचने के लिए इसके तीर का अनुसरण करता है। हो सकता है कि लक्ष्य पॉइंटी स्टेट को देख रहा हो या पॉइंटी स्टेट को बदल सकता हो। एक पॉइंटर पर डेरेक्शन ऑपरेशन केवल तभी काम करता है जब पॉइंटर में एक पॉइंटी होती है - पॉइंटी को आवंटित किया जाना चाहिए और पॉइंटर को इंगित करने के लिए सेट किया जाना चाहिए। पॉइंटर कोड में सबसे आम त्रुटि पॉइंटर को सेट करने के लिए भूल रही है। कोड में उस त्रुटि के कारण सबसे आम रनटाइम क्रैश एक विफल डेरेफेरेंस ऑपरेशन है। जावा में रनवे सिस्टम द्वारा गलत तरीके से झंडे को हरी झंडी दिखाई जाएगी। संकलित भाषाओं में जैसे कि C, C ++, और पास्कल, कभी-कभी गलत रूप से दुर्घटनाग्रस्त हो जाते हैं, और कुछ सूक्ष्म, यादृच्छिक तरीके से दूसरी बार भ्रष्ट स्मृति।
void main() {
int* x; // Allocate the pointer x
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
}
मुझे लगता है कि पिछले सभी उत्तर गलत हैं, क्योंकि वे कहते हैं कि डेरेफेरिंग का अर्थ वास्तविक मूल्य तक पहुंचना है। विकिपीडिया इसके बजाय सही परिभाषा देता है: https://en.wikipedia.org/wiki/Dereference_operator
यह एक पॉइंटर चर पर संचालित होता है, और पॉइंटर पते पर मूल्य के बराबर एक एल-मूल्य देता है। इसे पॉइंटर "डेरेफेरिंग" कहा जाता है।
उस ने कहा, हम पॉइंटर को कभी भी उस मूल्य तक पहुंच के बिना डीरेल कर सकते हैं जो इसे इंगित करता है। उदाहरण के लिए:
char *p = NULL;
*p;
हमने इसकी कीमत तक पहुँच के बिना NULL पॉइंटर को निष्क्रिय कर दिया है। या हम कर सकते हैं:
p1 = &(*p);
sz = sizeof(*p);
फिर, dereferencing, लेकिन कभी भी मूल्य का उपयोग नहीं किया। ऐसे कोड से दुर्घटना नहीं होगी: दुर्घटना तब होती है जब आप वास्तव में पहुंचते हैं में एक अमान्य पॉइंटर द्वारा डेटा का करते हैं। हालांकि, दुर्भाग्य से, मानक के अनुसार, एक अवैध सूचक को निष्क्रिय करना एक अपरिभाषित व्यवहार (कुछ अपवादों के साथ) है, भले ही आप वास्तविक डेटा को छूने की कोशिश न करें।
तो संक्षेप में: सूचक को डीरेफेरेंस करने का अर्थ है इसमें डीरेफेरेंस ऑपरेटर को लागू करना। वह ऑपरेटर सिर्फ आपके भविष्य के उपयोग के लिए एक एल-मूल्य लौटाता है।
*p;
अपरिभाषित व्यवहार का कारण बनता है। हालाँकि आप सही कह रहे हैं कि dereferencing प्रति se मान का उपयोग नहीं करता है , कोड मान का उपयोग *p;
करता है ।