दिलचस्प पोस्ट
बैस स्क्रिप्ट प्रोसेसिंग कमांड में समानांतर QueryPerformanceCounter का उपयोग कैसे करें? नक्शा कार्यों की संख्या निर्धारित करना और कार्यों को कम करना एंड्रॉइड स्टूडियो – एंड्रॉइड एसडीके पथ को कैसे बदलें MySQL डाटाबेस के साथ पायथन 3.4.0 Mod_php क्या है? SQL सर्वर तालिका से यादृच्छिक पंक्तियों का चयन करें किसी संख्या के विभाजन उत्पन्न करना मैं अतुल्यकालिक XMLHttpRequest के लिए कॉलबैक फ़ंक्शन का लाभ कैसे प्राप्त करूं? दृष्टिकोण के माध्यम से आर में ईमेल भेज रहा है एचटीएमएल पर कौन सी अक्षर बच निकलने की आवश्यकता है? मैं बटन पर क्लिक करने पर फॉर्म सबमिशन कैसे रद्द कर सकता हूं? गैर-अंग्रेजी अक्षरों से मिलान करने के लिए नियमित अभिव्यक्ति? सीएसएस का प्रयोग करके आईई 8 में अक्षम एचटीएमएल कंट्रोल का रंग कैसे बदल सकता है तार की सदिश को स्ट्रिंग में कैसे छूना (शानदार तरीका)

एक सी पॉइंटर वास्तव में क्या नहीं है, तो मेमोरी एड्रेस क्या है?

सी के बारे में एक सम्मानित स्रोत में, निम्न जानकारी & ऑपरेटर पर चर्चा के बाद दी गई है:

… यह दुर्भाग्यपूर्ण है कि शब्दावली [का पता] बनी हुई है, क्योंकि यह उन लोगों को भ्रमित करता है जो पता नहीं है कि कौन-से पते हैं, और जो लोग करते हैं, उन्हें गुमराह करता है: पॉइंटर्स के बारे में सोचकर जैसे वे पतों पर आमतौर पर दुःख की ओर जाते हैं .. ।

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

अब मैं थोड़ा उलझन में हूँ – क्या वास्तव में एक सूचक है, फिर, यदि नहीं तो मेमोरी पता?

पुनश्च

लेखक बाद में कहता है: … मैं 'एड्रेस ऑफ' शब्द का प्रयोग जारी रखूंगा, क्योंकि एक अलग एक [शब्द] का आविष्कार करने के लिए भी बदतर होगा

वेब के समाधान से एकत्रित समाधान "एक सी पॉइंटर वास्तव में क्या नहीं है, तो मेमोरी एड्रेस क्या है?"

सी मानक यह निर्धारित नहीं करता कि सूचक आंतरिक रूप से क्या है और यह आंतरिक रूप से कैसे काम करता है। यह जानबूझकर है क्योंकि प्लेटफार्मों की संख्या को सीमित करने के लिए नहीं, जहां सी को संकलित या व्याख्या की गई भाषा के रूप में लागू किया जा सकता है।

एक पॉइंटर वैल्यू कुछ प्रकार की आईडी या संभाल या कई आईडी के संयोजन हो सकता है (x86 सेगमेंट और ऑफ़सेट पर हैलो कहें) और जरूरी नहीं कि एक वास्तविक मेमोरी एड्रेस। यह आईडी कुछ भी हो सकती है, यहां तक ​​कि एक निश्चित आकार की टेक्स्ट स्ट्रिंग भी। गैर-पता प्रस्तुतीकरण एक सी व्याख्याता के लिए विशेष रूप से उपयोगी हो सकता है।

मुझे आपके स्रोत के बारे में निश्चित नहीं है, लेकिन आप जिस प्रकार की भाषा का वर्णन कर रहे हैं वह सी मानक से आता है:

6.5.3.2 पता और इंडिरेक्शन ऑपरेटर
[…]
3. यूनरी एंड ऑपरेटर इसके ऑपरेंड का पता अर्जित करता है। […]

तो … हाँ, पॉइंटर्स मेमोरी पतों को इंगित करते हैं। कम से कम यह है कि सी मानक इसका मतलब क्या है।

यह थोड़ा और स्पष्ट रूप से कहने के लिए, एक सूचक एक वेरिएबल है जो कुछ पते के मान को धारण करता है। किसी ऑब्जेक्ट का पता (जो कि सूचक में संग्रहीत किया जा सकता है) को यूनरी & ऑपरेटर के साथ वापस किया जाता है।

मैं एक चर में "42 वालबाई वे, सिडनी" पते को स्टोर कर सकता हूं (और वह वैरिएबल एक प्रकार का "संकेतक" होगा, लेकिन चूंकि यह एक मेमोरी एड्रेस नहीं है, ऐसा कुछ नहीं है जिसे हम ठीक से "पॉइंटर" कहते हैं)। आपके कंप्यूटर में स्मृति की अपनी बाल्टी के लिए पते हैं संकेतक एक पते के मूल्य को संचित करते हैं (यानी एक संकेतक "42 वालबाई वे, सिडनी" मानता है, जो एक पता है)।

संपादित करें: मैं एलेक्सी फ्रुंज़ की टिप्पणी पर विस्तार करना चाहता हूं।

वास्तव में एक संकेतक क्या है? चलो सी मानक को देखें:

6.2.5 प्रकार
[…]
20. […]
एक सूचक प्रकार फ़ंक्शन प्रकार या ऑब्जेक्ट प्रकार से प्राप्त किया जा सकता है, जिसे संदर्भित प्रकार कहा जाता है। एक सूचक प्रकार एक ऑब्जेक्ट का वर्णन करता है जिसका मान संदर्भित प्रकार के एक इकाई के संदर्भ प्रदान करता है। संदर्भित प्रकार टी से प्राप्त एक सूचक प्रकार को कभी-कभी '' सूचक को टी '' कहा जाता है। संदर्भित प्रकार से एक सूचक प्रकार का निर्माण '' सूचक प्रकार व्युत्पत्ति '' कहा जाता है। एक सूचक प्रकार एक पूर्ण वस्तु प्रकार है।

अनिवार्य रूप से, संकेतक एक मान संग्रहीत करते हैं जो किसी ऑब्जेक्ट या फ़ंक्शन के संदर्भ प्रदान करता है। एक प्रकार का। संकेतक किसी ऐसे वस्तु को संग्रहित करने का इरादा रखते हैं जो किसी ऑब्जेक्ट या फ़ंक्शन के संदर्भ प्रदान करता है, लेकिन यह हमेशा मामला नहीं होता है:

6.3.2.3 संकेतक
[…]
5. एक पूर्णांक किसी भी सूचक प्रकार में परिवर्तित किया जा सकता है। पूर्व में निर्दिष्ट के अलावा, परिणाम कार्यान्वयन-परिभाषित है, ठीक से गठबंधन नहीं हो सकता है, वह संदर्भित प्रकार की इकाई को इंगित नहीं कर सकता है, और यह एक जाल प्रतिनिधित्व हो सकता है।

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

तो हां, जैसे एलेक्सी फ्रुंज़े कहते हैं, यह संभव है कि सूचक एक ऑब्जेक्ट या फ़ंक्शन के लिए एक पते को संचित नहीं कर रहा है। यह संभव है कि कोई संकेतक किसी प्रकार के "हैंडल" या आईडी को संचित करता है, और आप ऐसा कर सकते हैं कि एक सूचक के लिए कुछ मनमानी पूर्णांक मान निर्दिष्ट करें। यह संभाल या आईडी का प्रतिनिधित्व सिस्टम / पर्यावरण / संदर्भ पर निर्भर करता है जब तक आपका सिस्टम / कार्यान्वयन मूल्य का अर्थ समझ सकता है, तब तक आप अच्छी स्थिति में हैं (लेकिन यह विशिष्ट मान और विशिष्ट सिस्टम / अनुमापन पर निर्भर करता है)।

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

यह समाप्त हो गया था कि मैंने सोचा था कि यह होगा …

पॉइंटर बनाम वैरिएबल

इस तस्वीर में,

pointer_p एक सूचक है जो 0x12345 पर स्थित है, और 0x34567 पर एक चर variable_v की ओर इशारा कर रहा है।

एक सूचक के रूप में एक सूचक के बारे में सोचना एक अनुमान है । सभी अनुमानों की तरह, कभी-कभी उपयोगी होने के लिए यह बहुत अच्छा होता है, लेकिन यह भी सटीक नहीं है जिसका मतलब है कि उस पर निर्भर होने से परेशानी होती है।

एक सूचक एक ऐसे पते की तरह है, जिसमें यह इंगित करता है कि ऑब्जेक्ट कहां से निकालना है। इस सादृश्य की एक तात्कालिक सीमा यह है कि सभी संकेतकों में वास्तव में कोई पता नहीं होता है। NULL एक सूचक है जो एक पता नहीं है। एक सूचक चर की सामग्री वास्तव में तीन प्रकारों में से एक हो सकती है:

  • किसी वस्तु का पता , जिसे dereferenced किया जा सकता है (यदि p में x का पता होता है तो एक्सप्रेशन *p का x रूप में समान मान होता है);
  • एक अशक्त सूचक , जिसमें से NULL एक उदाहरण है;
  • अमान्य सामग्री, जो किसी ऑब्जेक्ट को इंगित नहीं करती है (यदि p कोई मान्य मान नहीं है, तो *p कुछ भी कर सकता है ("अपरिभाषित व्यवहार"), कार्यक्रम को काफी सामान्य संभावना को क्रैश करने के साथ)

इसके अलावा, यह कहना सही होगा कि एक संकेतक (यदि वैध और गैर-अशक्त) में एक पता होता है: एक संकेतक इंगित करता है कि ऑब्जेक्ट कहां से है, लेकिन इसके साथ बनी जानकारी अधिक है

विशेष रूप से, एक सूचक एक प्रकार है। अधिकांश प्लेटफार्मों पर, रनटाइम पर पॉइंटर का प्रकार का कोई प्रभाव नहीं होता है, लेकिन उसका एक प्रभाव होता है जो कि संकलन समय पर प्रकार से परे जाता है। यदि p int ( int *p; ) के लिए एक सूचक है, तो एक पूर्णांक को p + 1 अंक जो p बाद sizeof(int) बाइट्स है ( p + 1 मानते हुए भी एक मान्य सूचक है)। यदि q char लिए एक सूचक है, जो p ( char *q = p; ) के समान पते को इंगित करता है, तो q + 1 p + 1 के समान पता नहीं है यदि आप सूचक के पते के रूप में सोचते हैं, तो यह बहुत ही सहज नहीं है कि "अगला पता" एक ही स्थान पर अलग-अलग पॉइंटर्स के लिए अलग है।

कुछ वातावरण में संभव है कि विभिन्न सूचकों (स्मृति में अलग-अलग बिट पैटर्न) के साथ एकाधिक पॉइंटर मान हो जो स्मृति में एक ही स्थान पर इंगित हो। आप इन्हें एक ही पते वाले विभिन्न संकेतक के रूप में, या एक ही स्थान के लिए अलग-अलग पते के रूप में सोच सकते हैं – इस मामले में रूपक स्पष्ट नहीं है। == ऑपरेटर हमेशा आपको बताता है कि दो ऑपरेंड एक ही स्थान पर इशारा कर रहे हैं या नहीं, इसलिए इन परिवेशों पर आपके पास p == q सकता है, फिर भी p और q में अलग-अलग बिट पैटर्न हैं।

ऐसे वातावरण भी हैं जहां संकेतक पते से परे अन्य जानकारी लेते हैं, जैसे प्रकार या अनुमति जानकारी इनका सामना किए बिना आप आसानी से एक प्रोग्रामर के रूप में अपने जीवन में जा सकते हैं।

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

बिल्कुल भी, संकेतक के रूप में पते के बारे में सोच बहुत बुरा नहीं है जब तक कि आप ध्यान में रखते हैं कि

  • यह केवल वैध, गैर-रिक्त संकेतक हैं जो पते हैं;
  • आप एक ही स्थान के लिए एकाधिक पते हो सकते हैं;
  • आप पते पर अंकगणित नहीं कर सकते, और उन पर कोई आदेश नहीं है;
  • सूचक भी प्रकार की जानकारी देता है

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

पहले कुछ प्रसिद्ध सीमाएं हैं; उदाहरण के लिए, एक पूर्णांक जो आपके प्रोग्राम के पता स्थान के बाहर स्थान निर्दिष्ट करता है, वह मान्य सूचक नहीं हो सकता है एक ग़लत संरेखित पता संरेखण की आवश्यकता वाले डेटा प्रकार के लिए एक वैध सूचक नहीं करता है; उदाहरण के लिए, एक प्लेटफॉर्म पर जहां int आवश्यकता है 4-बाइट संरेखण, 0x7654321 मान्य int* मान नहीं हो सकता।

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

 unsigned int x = 0; unsigned short *p = (unsigned short*)&x; p[0] = 1; printf("%u = %u\n", x, *p); 

आप उम्मीद कर सकते हैं कि रन-ऑफ-द-मिल मशीन पर जहां sizeof(int)==4 और sizeof(short)==2 , यह या तो 1 = 1? प्रिंट करता है 1 = 1? (कम-एंडियन) या 65536 = 1? (बड़े एंडियन)। लेकिन जीसीसी 4.4 के साथ मेरे 64-बिट लिनक्स पीसी पर:

 $ c99 -O2 -Wall ac && ./a.out ac: In function 'main': ac:6: warning: dereferencing pointer 'p' does break strict-aliasing rules ac:5: note: initialized from here 0 = 1? 

जीसीसी काफी सावधान है कि हमें इस सरल उदाहरण में क्या गलत हो रहा है – अधिक जटिल उदाहरणों में, कंपाइलर को ध्यान नहीं दिया जा सकता है। चूंकि p में एक अलग प्रकार का है &x , जो पॉइंट्स को इंगित करता है वह क्या &x अंक को प्रभावित नहीं कर सकता है (कुछ अच्छी तरह से परिभाषित अपवादों के बाहर)। इसलिए कंपाइलर एक रजिस्टर में x के मूल्य को रखने के लिए स्वतंत्रता पर है और इस रजिस्टर को *p अपडेट न करें। कार्यक्रम एक ही पते पर दो बिंदुओं को दोरेन्द्र करता है और दो अलग-अलग मूल्यों को प्राप्त करता है!

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

तो सोचें कि संकेतक आपकी समझ में पहले चरण के रूप में पतों हैं, लेकिन उस अंतर्ज्ञान का पालन बहुत दूर नहीं है।

एक सूचक एक वेरिएबल है जो होल्डस मेमोरी एड्रेस है, न ही पता है। हालांकि, आप पॉइंटर को दुबारा कर सकते हैं – और मेमोरी स्थान पर पहुंच प्राप्त कर सकते हैं।

उदाहरण के लिए:

 int q = 10; /*say q is at address 0x10203040*/ int *p = &q; /*means let p contain the address of q, which is 0x10203040*/ *p = 20; /*set whatever is at the address pointed by "p" as 20*/ 

बस। यह इत्ना आसान है।

यहां छवि विवरण दर्ज करें

मैं क्या कह रहा हूं, इसका प्रदर्शन करने वाला एक कार्यक्रम और इसके उत्पादन यहां है:

http://ideone.com/rcSUsb

कार्यक्रम:

 #include <stdio.h> int main(int argc, char *argv[]) { /* POINTER AS AN ADDRESS */ int q = 10; int *p = &q; printf("address of q is %p\n", (void *)&q); printf("p contains %p\n", (void *)p); p = NULL; printf("NULL p now contains %p\n", (void *)p); return 0; } 

यह बिल्कुल बताना मुश्किल है कि उन पुस्तकों के लेखकों का वास्तव में क्या मतलब है संकेतक में एक पता है या नहीं, यह निर्भर करता है कि आप एक पते को कैसे परिभाषित करते हैं और आप एक संकेतक कैसे परिभाषित करते हैं।

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

हालांकि, हम देखते हैं कि (2) शायद सच है, (1) संभवत: सच होना जरूरी नहीं है और क्या तथ्य है कि & quot; Cornstalks के उत्तर के अनुसार ऑपरेटर का पता कहा जाता है? क्या इसका मतलब यह है कि विनिर्देश के लेखक एक संकेतक के लिए एक पते को शामिल करना चाहते हैं?

तो क्या हम कह सकते हैं, सूचक में एक पता है, लेकिन एक पता एक पूर्णांक नहीं है? शायद।

मुझे लगता है कि यह सब पलटवानी अर्थपूर्ण बात है। यह पूरी तरह से बेकार है व्यावहारिक रूप से बोल रहा है। क्या आप ऐसे कंपाइलर के बारे में सोच सकते हैं जो इस तरह से कोड उत्पन्न करता है कि सूचक का मान एक पता नहीं है? यदि ऐसा है तो क्या? बिल्कुल यही मैने सोचा…

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

उदाहरण के लिए,

  int x; int* y = &x; char* z = &x; 

दोनों y और z संकेतक होते हैं, लेकिन y + 1 और z + 1 अलग होते हैं। अगर वे मेमोरी पतों हैं, तो क्या वे एक्सप्रेशन आपको समान मूल्य नहीं देंगे?

और यहां संकेतक के बारे में सोचने में झूठ है जैसे कि वे पते पर आमतौर पर दुःख की ओर जाता है बग्स लिखी गई हैं क्योंकि लोगों को पॉइंटर्स के बारे में सोचते हैं जैसे वे पतों के बारे में सोचते हैं , और यह आमतौर पर दुःख की ओर जाता है

55555 शायद एक संकेतक नहीं है, हालांकि यह एक पता हो सकता है, लेकिन (इंट *) 55555 एक सूचक है 55555 + 1 = 55556, लेकिन (इंट *) 55555 + 1 55559 है (+/- आकार के मामले में अंतर (इंट))।

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

दुःख का सबसे अधिक संभावना स्रोत निश्चित तौर पर सूचक अंकगणित है, जो वास्तव में सी की ताकत में से एक है यदि कोई संकेतक एक पता था, तो आप संकेतक अंकगणित को अंकगणित होने की उम्मीद करेंगे; लेकिन ऐसा नहीं है। उदाहरण के लिए, एक पते पर 10 जोड़कर आपको 10 पता करने वाले यूनिट्स से बड़ा पता होना चाहिए; लेकिन 10 से एक पॉइंटर को 10 ऑब्जेक्ट्स के आकार के ऑब्जेक्ट के आकार में जोड़ता है, जो उस ऑब्जेक्ट के आकार का होता है (और यहां तक ​​कि वास्तविक आकार भी नहीं, बल्कि एक संरेखण सीमा तक गोल होता है)। 32-बिट पूर्णांकों के साथ एक सामान्य आर्किटेक्चर पर int * साथ, 10 जोड़कर इसे 40 एड्रेसिंग यूनिट (बाइट्स) द्वारा बढ़ा दिया जाएगा। अनुभवी सी प्रोग्रामर इस बारे में जानते हैं और इसके साथ रहते हैं, लेकिन आपका लेखक स्पष्ट रूप से ढीली रूपकों का कोई प्रशंसक नहीं है।

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

यहां बताया गया है कि मैंने इसे अतीत में कुछ भ्रमित लोगों को समझाया है: एक सूचक के दो गुण हैं जो उसके व्यवहार को प्रभावित करते हैं। इसका मान है , जो (सामान्य वातावरण में) एक मेमोरी एड्रेस है, और एक प्रकार है , जो आपको ऑब्जेक्ट के प्रकार और आकार बताता है जिस पर यह इंगित करता है।

उदाहरण के लिए, दिए गए:

 union { int i; char c; } u; 

आपके पास तीन अलग-अलग पॉइंटर्स हो सकते हैं जो सभी इस वही वस्तु की ओर इशारा करते हैं:

 void *v = &u; int *i = &u.i; char *c = &u.c; 

यदि आप इन पॉइंटर्स के मूल्यों की तुलना करते हैं, तो वे सभी समान हैं:

 v==i && i==c 

हालांकि, यदि आप प्रत्येक सूचक को बढ़ाते हैं, तो आप देखेंगे कि वे जो प्रकार इंगित करते हैं वह प्रासंगिक हो जाता है

 i++; c++; // You can't perform arithmetic on a void pointer, so no v++ i != c 

इस बिंदु पर चर i और c पास अलग-अलग मान होंगे, क्योंकि i++ कारण i अगले-सुलभ पूर्णांक के पते को शामिल करता i , और c++ को अगले-पता योग्य वर्ण को इंगित करने के लिए कारण देता है। आमतौर पर, पूर्णांक वर्णों की तुलना में अधिक मेमोरी लेते हैं, इसलिए i c से बड़ा मान समाप्त कर देता i , क्योंकि वे दोनों वृद्धिशील हैं।

सी में किसी भी अन्य चर की तरह एक सूचक, मूल रूप से बिट्स का एक संग्रह होता है जिसे एक या एक से अधिक संकीर्ण unsigned char मूल्यों (किसी भी अन्य प्रकार के तार, sizeof(some_variable) में दिखाया जा सकता है, unsigned char मूल्यों की संख्या को दर्शाता है) । क्या अन्य चर से एक संकेतक अलग होता है, यह है कि सी कंपाइलर एक सूचक में बिट्स की व्याख्या करेगा, किसी भी तरह, एक जगह जहां एक चर संग्रहीत किया जा सकता है। सी में, कुछ अन्य भाषाओं के विपरीत, कई चर के लिए जगह का अनुरोध करना संभव है, और फिर उस सूचक में किसी भी मान को उस सेट में किसी भी अन्य चर में सूचक के रूप में सेट कर सकते हैं।

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

ध्यान दें कि जब पॉइंटर्स कुछ हद तक सारभूत होते हैं, तो वे कचरा कलेक्टर को कार्यान्वित करने के लिए एक पूर्ण-मानक-अनुपालन सी संकलक को अनुमति देने के लिए पर्याप्त रूप से पर्याप्त नहीं हैं। सी कंपाइलर निर्दिष्ट करता है कि प्रत्येक चर, पॉइंटर्स समेत, unsigned char मानों के अनुक्रम के रूप में दर्शाया गया है। किसी भी वैरिएबल को देखते हुए, यह संख्याओं के अनुक्रम में विघटित हो सकता है और बाद में उस क्रम की संख्या को मूल प्रकार के वेरिएबल में परिवर्तित कर सकता है। नतीजतन, एक प्रोग्राम को कुछ स्टोरेज को calloc करने के लिए संभव होगा (इसमें एक पॉइंटर calloc ), वहां कुछ स्टोर करे, पॉइंटर को बाइट्स की एक श्रृंखला में विघटित करें, स्क्रीन पर प्रदर्शित करें, और उसके बाद सभी संदर्भ मिटा दें। अगर कार्यक्रम ने कीबोर्ड से कुछ संख्या स्वीकार कर ली, तो उन्हें पॉइंटर पर पुनर्गठन किया गया, और फिर उस पॉइंटर से डेटा पढ़ने की कोशिश की, और अगर उपयोगकर्ता ने उसी संख्या में प्रवेश किया जो पहले प्रोग्राम प्रदर्शित किया गया था, तो प्रोग्राम को डेटा आउटपुट करने की आवश्यकता होगी जो calloc 'एड मेमोरी में संग्रहीत किया गया था चूंकि कंप्यूटर को पता नहीं चल पाया जा सकता है कि उपयोगकर्ता क्या संख्याओं की प्रतिलिपि बना चुके हैं, जो कि प्रदर्शित किए गए थे, कोई कल्पना नहीं होगी, कंप्यूटर यह जान सकता है कि भविष्य में भविष्य में पहले से कहीं ज्यादा स्मृति का उपयोग किया जा सकता है या नहीं।

Mark Bessey already said it, but this needs to be re-emphasised until understood.

Pointer has as much to do with a variable than a literal 3.

Pointer is a tuple of a value (of an address) and a type (with additional properties, such as read only). The type (and the additional parameters if any) can further define or restrict the context; जैसे। __far ptr, __near ptr : what is the context of the address: stack, heap, linear address, offset from somewhere, physical memory or what.

It's the property of type that makes pointer arithmetic a bit different to integer arithmetic.

The counter examples of a pointer of not being a variable are too many to ignore

  • fopen returning a FILE pointer. (where's the variable)
  • stack pointer or frame pointer being typically unaddressable registers

    *(int *)0x1231330 = 13; — casting an arbitrary integer value to a pointer_of_integer type and writing/reading an integer without ever introducing a variable

In the lifetime of a C-program there will be many other instances of temporary pointers that do not have addresses — and therefore they are not variables, but expressions/values with a compile time associated type.

You are right and sane. Normally, a pointer is just an address, so you can cast it to integer and do any arithmetics.

But sometimes pointers are only a part of an address. On some architectures a pointer is converted to an address with addition of base or another CPU register is used.

But these days, on PC and ARM architecture with a flat memory model and C language natively compiled, it's OK to think that a pointer is an integer address to some place in one-dimensional addressable RAM.

A pointer is a variable type that is natively available in C/C++ and contains a memory address. Like any other variable it has an address of its own and takes up memory (the amount is platform specific).

One problem you will see as a result of the confusion is trying to change the referent within a function by simply passing the pointer by value. This will make a copy of the pointer at function scope and any changes to where this new pointer "points" will not change the referent of the pointer at the scope that invoked the function. In order to modify the actual pointer within a function one would normally pass a pointer to a pointer.

BRIEF SUMMARY (which I will also put at the top):

(0) Thinking of pointers as addresses is often a good learning tool, and is often the actual implementation for pointers to ordinary data types.

(1) But on many, perhaps most, compilers pointers to functions are not addresses, but are bigger than an address (typically 2x, sometimes more), or are actually pointers to a struct in memory than contains the addresses of function and stuff like a constant pool.

(2) Pointers to data members and pointers to methods are often even stranger.

(3) Legacy x86 code with FAR and NEAR pointer issues

(4) Several examples, most notably the IBM AS/400, with secure "fat pointers".

I am sure you can find more.

DETAIL:

UMMPPHHH!!!!! Many of the answers so far are fairly typical "programmer weenie" answers – but not compiler weenie or hardware weenie. Since I pretend to be a hardware weenie, and often work with compiler weenies, let me throw in my two cents:

On many, probably most, C compilers, a pointer to data of type T is, in fact, the address of T .

ठीक।

But, even on many of these compilers, certain pointers are NOT addresses. You can tell this by looking at sizeof(ThePointer) .

For example, pointers to functions are sometimes quite a lot bigger than ordinary addresses. Or, they may involve a level of indirection. This article provides one description, involving the Intel Itanium processor, but I have seen others. Typically, to call a function you must know not only the address of the function code, but also the address of the function's constant pool – a region of memory from which constants are loaded with a single load instruction, rather than the compiler having to generate a 64 bit constant out of several Load Immediate and Shift and OR instructions. So, rather than a single 64 bit address, you need 2 64 bit addresses. Some ABIs (Application Binary Interfaces) move this around as 128 bits, whereas others use a level of indirection, with the function pointer actually being the address of a function descriptor that contains the 2 actual addresses just mentioned. कौनसा अच्छा है? Depends on your point of view: performance, code size, and some compatibility issues – often code assumes that a pointer can be cast to a long or a long long, but may also assume that the long long is exactly 64 bits. Such code may not be standards compliant, but nevertheless customers may want it to work.

Many of us have painful memories of the old Intel x86 segmented architecture, with NEAR POINTERs and FAR POINTERS. Thankfully these are nearly extinct by now, so only a quick summary: in 16 bit real mode, the actual linear address was

 LinearAddress = SegmentRegister[SegNum].base << 4 + Offset 

Whereas in protected mode, it might be

 LinearAddress = SegmentRegister[SegNum].base + offset 

with the resulting address being checked against a limit set in the segment. Some programs used not really standard C/C++ FAR and NEAR pointer declarations, but many just said *T — but there were compiler and linker switches so, for example, code pointers might be near pointers, just a 32 bit offset against whatever is in the CS (Code Segment) register, while the data pointers might be FAR pointers, specifying both a 16 bit segment number and a 32 bit offset for a 48 bit value. Now, both of these quantities are certainly related to the address, but since they aren't the same size, which of them is the address? Moreover, the segments also carried permissions – read-only, read-write, executable – in addition to stuff related to the actual address.

A more interesting example, IMHO, is (or, perhaps, was) the IBM AS/400 family. This computer was one of the first to implement an OS in C++. Pointers on this machime were typically 2X the actual address size – eg as this presentation says, 128 bit pointers, but the actual addresses were 48-64 bits, and, again, some extra info, what is called a capability, that provided permissions such as read, write, as well as a limit to prevent buffer overflow. Yes: you can do this compatibly with C/C++ — and if this were ubiquitous, the Chinese PLA and slavic mafia would not be hacking into so many Western computer systems. But historically most C/C++ programming has neglected security for performance. Most interestingly, the AS400 family allowed the operating system to create secure pointers, that could be given to unprivileged code, but which the unprivileged code could not forge or tamper with. Again, security, and while standards compliant, much sloppy non-standards compliant C/C++ code will not work in such a secure system. Again, there are official standards, and there are de-facto standards.

Now, I'll get off my security soapbox, and mention some other ways in which pointers (of various types) are often not really addresses: Pointers to data members, pointers to member functions methods, and the static versions thereof are bigger than an ordinary address. As this post says:

There are many ways of solving this [problems related to single versus multiple inheitance, and virtual inheritance]. Here's how the Visual Studio compiler decides to handle it: A pointer to a member function of a multiply-inherited class is really a structure." And they go on to say "Casting a function pointer can change its size!".

As you can probably guess from my pontificating on (in)security, I've been involved in C/C++ hardware/software projects where a pointer was treated more like a capability than a raw address.

I could go on, but I hope you get the idea.

BRIEF SUMMARY (which I will also put at the top):

(0) thinking of pointers as addresses is often a good learning tool, and is often the actual implementation for pointers to ordinary data types.

(1) But on many, perhaps most, compilers pointers to functions are not addresses, but are bigger than an address (typically 2X, sometimes more), or are actually pointers to a struct in memory than contains the addresses of function and stuff like a constant pool.

(2) Pointers to data members and pointers to methods are often even stranger.

(3) Legacy x86 code with FAR and NEAR pointer issues

(4) Several examples, most notably the IBM AS/400, with secure "fat pointers".

I am sure you can find more.

A pointer is just another variable which is used to hold the address of a memory location (usually the memory address of another variable).

You can see it this way. A pointer is a value that represents an address in the addressable memory space.

A pointer is just another variable that can contain memory address usually of another variable. A pointer being a variable it too has an memory address.

AC pointer is very similar to a memory address but with machine-dependent details abstracted away, as well as some features not found in the lower level instruction set.

For example, a C pointer is relatively richly typed. If you increment a pointer through an array of structures, it nicely jumps from one structure to the other.

Pointers are subject to conversion rules and provide compile time type checking.

There is a special "null pointer" value which is portable at the source code level, but whose representation may differ. If you assign an integer constant whose value is zero to a pointer, that pointer takes on the null pointer value. Ditto if you initialize a pointer that way.

A pointer can be used as a boolean variable: it tests true if it is other than null, and false if it is null.

In a machine language, if the null pointer is a funny address like 0xFFFFFFFF, then you may have to have explicit tests for that value. C hides that from you. Even if the null pointer is 0xFFFFFFFF, you can test it using if (ptr != 0) { /* not null! */} .

Uses of pointers which subvert the type system lead to undefined behavior, whereas similar code in machine language might be well defined. Assemblers will assemble the instructions you have written, but C compilers will optimize based on the assumption that you haven't done anything wrong. If a float *p pointer points to a long n variable, and *p = 0.0 is executed, the compiler is not required to handle this. A subsequent use of n will not necessary read the bit pattern of the float value, but perhaps, it will be an optimized access which is based on the "strict aliasing" assumption that n has not been touched! That is, the assumption that the program is well-behaved, and so p should not be pointing at n .

In C, pointers to code and pointers to data are different, but on many architectures, the addresses are the same. C compilers can be developed which have "fat" pointers, even though the target architecture does not. Fat pointers means that pointers are not just machine addresses, but contain other info, such as information about the size of the object being pointed at, for bounds checking. Portably written programs will easily port to such compilers.

So you can see, there are many semantic differences between machine addresses and C pointers.

Before understanding pointers we need to understand objects. Objects are entities which exist and has a location specifier called an address. A pointer is just a variable like any other variables in C with a type called pointer whose content is interpreted as the address of an object which supports the following operation.

 + : A variable of type integer (usually called offset) can be added to yield a new pointer - : A variable of type integer (usually called offset) can be subtracted to yield a new pointer : A variable of type pointer can be subtracted to yield an integer (usually called offset) * : De-referencing. Retrieve the value of the variable (called address) and map to the object the address refers to. ++: It's just `+= 1` --: It's just `-= 1` 

A pointer is classified based on the type of object it is currently referring. The only part of the information it matters is the size of the object.

Any object supports an operation, & (address of), which retrieves the location specifier (address) of the object as a pointer object type. This should abate the confusion surrounding the nomenclature as this would make sense to call & as an operation of an object rather than a pointer whose resultant type is a pointer of the object type.

Note Throughout this explanation, I have left out the concept of memory.

An address is used to identify a piece of fixed-size storage, usually for each bytes, as an integer. This is precisely called as byte address , which is also used by the ISO C. There can be some other methods to construct an address, eg for each bit. However, only byte address is so often used, we usually omit "byte".

Technically, an address is never a value in C, because the definition of term "value" in (ISO) C is:

precise meaning of the contents of an object when interpreted as having a specific type

(Emphasized by me.) However, there is no such "address type" in C.

Pointer is not the same. Pointer is a kind of type in the C language. There are several distinct pointer types. They does not necessarily obey to identical set of rules of the language, eg the effect of ++ on a value of type int* vs. char* .

A value in C can be of a pointer type. This is called a pointer value . To be clear, a pointer value is not a pointer in the C language. But we are accustomed to mix them together, because in C it is not likely to be ambiguous: if we call an expression p as a "pointer", it is merely a pointer value but not a type, since a named type in C is not expressed by an expression , but by a type-name or a typedef-name .

Some other things are subtle. As a C user, firstly, one should know what object means:

region of data storage in the execution environment, the contents of which can represent values

An object is an entity to represent values, which are of a specific type. A pointer is an object type . So if we declare int* p; , then p means "an object of pointer type", or an "pointer object".

Note there is no "variable" normatively defined by the standard (in fact it is never being used as a noun by ISO C in normative text). However, informally, we call an object a variable, as some other language does. (But still not so exactly, eg in C++ a variable can be of reference type normatively, which is not an object.) The phrases "pointer object" or "pointer variable" are sometimes treated like "pointer value" as above, with a probable slight difference. (One more set of examples is "array".)

Since pointer is a type, and address is effectively "typeless" in C, a pointer value roughly "contains" an address. And an expression of pointer type can yield an address, eg

ISO C11 6.5.2.3

3 The unary & operator yields the address of its operand.

Note this wording is introduced by WG14/N1256, ie ISO C99:TC3. In C99 there is

3 The unary & operator returns the address of its operand.

It reflects the committee's opinion: an address is not a pointer value returned by the unary & operator.

Despite the wording above, there are still some mess even in the standards.

ISO C11 6.6

9 An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator

ISO C++11 5.19

3 … An address constant expression is a prvalue core constant expression of pointer type that evaluates to the address of an object with static storage duration, to the address of a function, or to a null pointer value, or a prvalue core constant expression of type std::nullptr_t . …

(Recent C++ standard draft uses another wording so there is no this problem.)

Actually both "address constant" in C and "address constant expression" in C++ are constant expression of pointer types (or at least "pointer-like" types since C++11).

And the builtin unary & operator is called as "address-of" in C and C++; similarily, std::addressof is introduced in C++11.

These naming may bring misconception. The resulted expression is of pointer type, so they'd be interpreted as: the result contains/yields an address, rather than is an address.

It says "because it confuses those who don't know what addresses are about" – also, it's true: if you learn what addresses are about, you'll be not confused. Theoretically, pointer is a variable which points to another, practically holds an address, which is the address of the variable it points to. I don't know why should hide this fact, it's not a rocket science. If you understand pointers, you'll one step closer to understand how computers work. Go ahead!

Come to think about it, I think it's a matter of semantics. I don't think the author is right, since the C standard refers to a pointer as holding an address to the referenced object as others have already mentioned here. However, address!=memory address. An address can be really anything as per C standard although it will eventually lead to a memory address, the pointer itself can be an id, an offset + selector (x86), really anything as long as it can describe (after mapping) any memory address in the addressable space.

One other way in which a C or C++ pointer differs from a simple memory address due to the different pointer types I haven't seen in the other answers (altrhough given their total size, I may have overlooked it). But it is probably the most important one, because even experienced C/C++ programmers can trip over it:

The compiler may assume that pointers of incompatible types do not point to the same address even if they clearly do, which may give behaviour that would no be possible with a simple pointer==address model. Consider the following code (assuming sizeof(int) = 2*sizeof(short) ):

 unsigned int i = 0; unsigned short* p = (unsigned short*)&i; p[0]=p[1]=1; if (i == 2 + (unsigned short)(-1)) { // you'd expect this to execute, but it need not } if (i == 0) { // you'd expect this not to execute, but it actually may do so } 

Note that there's an exception for char* , so manipulating values using char* is possible (although not very portable).

Quick summary: AC address is a value, typically represented as a machine-level memory address, with a specific type.

The unqualified word "pointer" is ambiguous. C has pointer objects (variables), pointer types , pointer expressions , and pointer values .

It's very common to use the word "pointer" to mean "pointer object", and that can lead to some confusion — which is why I try to use "pointer" as an adjective rather than as a noun.

The C standard, at least in some cases, uses the word "pointer" to mean "pointer value". For example, the description of malloc says it "returns either a null pointer or a pointer to the allocated space".

So what's an address in C? It's a pointer value, ie, a value of some particular pointer type. (Except that a null pointer value is not necessarily referred to as an "address", since it isn't the address of anything).

The standard's description of the unary & operator says it "yields the address of its operand". Outside the C standard, the word "address" is commonly used to refer to a (physical or virtual) memory address, typically one word in size (whatever a "word" is on a given system).

AC "address" is typically implemented as a machine address — just as a C int value is typically implemented as a machine word. But a C address (pointer value) is more than just a machine address. It's a value typically represented as a machine address, and it's a value with some specific type .

A pointer value is an address. A pointer variable is an object that can store an address. This is true because that's what the standard defines a pointer to be. It's important to tell it to C novices because C novices are often unclear on the difference between a pointer and the thing it points to (that is to say, they don't know the difference between an envelope and a building). The notion of an address (every object has an address and that's what a pointer stores) is important because it sorts that out.

However, the standard talks at a particular level of abstraction. Those people the author talks about who "know what addresses are about", but who are new to C, must necessarily have learned about addresses at a different level of abstraction — perhaps by programming assembly language. There is no guarantee that the C implementation uses the same representation for addresses as the CPUs opcodes use (referred to as "the store address" in this passage), that these people already know about.

He goes on to talk about "perfectly reasonable address manipulation". As far as the C standard is concerned there's basically no such thing as "perfectly reasonable address manipulation". Addition is defined on pointers and that is basically it. Sure, you can convert a pointer to integer, do some bitwise or arithmetic ops, and then convert it back. This is not guaranteed to work by the standard, so before writing that code you'd better know how your particular C implementation represents pointers and performs that conversion. It probably uses the address representation you expect, but it it doesn't that's your fault because you didn't read the manual. That's not confusion, it's incorrect programming procedure 😉

In short, C uses a more abstract concept of an address than the author does.

The author's concept of an address of course is also not the lowest-level word on the matter. What with virtual memory maps and physical RAM addressing across multiple chips, the number that you tell the CPU is "the store address" you want to access has basically nothing to do with where the data you want is actually located in hardware. It's all layers of indirection and representation, but the author has chosen one to privilege. If you're going to do that when talking about C, choose the C level to privilege !

Personally I don't think the author's remarks are all that helpful, except in the context of introducing C to assembly programmers. It's certainly not helpful to those coming from higher level languages to say that pointer values aren't addresses. It would be far better to acknowledge the complexity than it is to say that the CPU has the monopoly on saying what an address is and thus that C pointer values "are not" addresses. They are addresses, but they may be written in a different language from the addresses he means. Distinguishing the two things in the context of C as "address" and "store address" would be adequate, I think.

Simply to say pointers are actually offset part of the segmentation mechanism which translate to Linear Address after segmentation and then to Physical address after paging. Physical Addresses are actually addressed from you ram.

  Selector +--------------+ +-----------+ ---------->| | | | | Segmentation | ------->| Paging | Offset | Mechanism | | Mechanism | ---------->| | | | +--------------+ +-----------+ Virtual Linear Physical