2011-02-14 18 views
9

अपसंदर्भन मैं एक बार चरित्र सरणियों (तार) की एक सरणी बनाता है कैसे char ** वास्तव में यह पूरा करता है char **चार ** और संकेत

के साथ मेरे भ्रम की स्थिति को समाप्त करने के चाहते हैं?

मैं कि char * एक चार के लिए सूचक है हो और कि char *array[] चार संकेत की एक सरणी है, लेकिन वास्तव में क्या करता है char ** करना है और कैसे यह यह क्या करता है?

इसके अलावा जब मैं वचन सुनने यह मुझे लगता है कि सूचक निकाल दिया जाता है वास्तव में एक संकेतक भिन्नता करता है क्या मतलब है बनाता है dereferences? सूचकांक को इंगित करने वाले मान को बदलना?

धन्यवाद

उत्तर

10

की तरह एक स्मृति आवंटन समारोह/ऑपरेटर से आते हैं "अपसंदर्भन" एक सूचक सूचक अंक के मूल्य तक पहुँचने का मतलब है। मान लें निम्नलिखित घोषणाओं:

int a = 10; 
int *p = &a; 

यहाँ दो चर का एक काल्पनिक स्मृति नक्शा है:

 
Item  Address  0x00 0x01 0x02 0x03 
----  -------  ---- ---- ---- ---- 
    a  0x80001000 0x00 0x00 0x00 0x0A 
    p  0x80001004 0x80 0x00 0x10 0x00 

a पूर्णांक मान से 10 pa (0x80001000) के पते शामिल हैं। अगर हम ap के माध्यम से dereferencep इंडिकेशन ऑपरेटर * के साथ सामग्री तक पहुंचना चाहते हैं। इस प्रकार, अभिव्यक्ति *p अभिव्यक्ति a के बराबर है।

#include <stdlib.h> 
#define N  20 // For this example, we will allocate 20 strings 
#define LENGTH 10 // of 10 characters each (not counting 0 terminator) 
... 
char **arr = malloc(sizeof *arr * N); 
if (arr) 
{ 
    size_t i; 
    for (i = 0; i < N; i++) 
    { 
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1)); 
    strcpy(arr[i], "   "); 
    } 
} 
: यदि हम

a = 16; 

लेखन के रूप में

*p = 16; 

ही है कि लिखा है यहाँ कैसे प्रकार char ** की एक वस्तु का उपयोग करने के तार की एक सरणी बनाने के लिए दिखा कोड का एक लघु स्निपेट है

लाइन के माध्यम से लाइन के माध्यम से जाना,

char **arr = malloc(sizeof *arr * N); 

एन तत्वों का एक ब्लॉक आबंटित करता है, पर्याप्त प्रत्येक बड़े एक सूचक चार करने के लिए (sizeof *arr == sizeof (char *)*arr == char * के प्रकार के बाद से) स्टोर करने के लिए, और arr के परिणामस्वरूप सूचक मूल्य प्रदान करती है। IOW, arr पहले पॉइंटर को char पर इंगित करता है, इसलिए char ** टाइप करें। ध्यान दें कि यदि आप घोषणा और समारोह कॉल अलग हो गए, यह नहीं क्या arrअंक की तरह

char **arr; 
... 
arr = malloc(sizeof *arr * N); 

हम arr को malloc का परिणाम प्रदान करना चाहते हैं लगेगा,।

if (arr) 

यह malloc विफल करने के लिए संभव है, इसलिए हम इसे उपयोग करने से पहले परिणाम की जांच करना चाहते। घटना में malloc विफल रहता है यह एक पूर्ण सूचक मूल्य वापस करेगा।

{ 
    size_t i; 
    for (i = 0; i < N; i++) 
    { 
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1)); 

हर किरदार के सूचक arr[i] के लिए, हम स्मृति काफी बड़ी लंबाई + 1 तत्वों के लिए, पर्याप्त प्रत्येक बड़े एक char मूल्य धारण करने के लिए के एक ब्लॉक का आवंटन (sizeof *arr[i] == sizeof (char), *arr[i] == char के प्रकार के बाद से, ध्यान दें कि sizeof (char) हमेशा होता है 1) और परिणाम arr[i] पर असाइन करें।

चूंकि हम अलग-अलग malloc कॉल के साथ प्रत्येक स्ट्रिंग आवंटित करते हैं, यह संभावना नहीं है कि वे स्मृति में सम्मिलित हैं। यहाँ एक और स्मृति एक संभव उपरोक्त कोड का परिणाम दिखा नक्शा है: "। * P1 == ग, अर्थात अपसंदर्भन p1 हमें/से पढ़ा ग लिखने के लिए अनुमति देता है"

 
Item   Address  0x00 0x01 0x02 0x03 
----   -------  ---- ---- ---- ---- 
arr   0x80001000  0xA0 0xCC 0x00 0x00 
      ... 
arr[0]  0xA0CC0000  0xA0 0xCC 0x20 0x00  
arr[1]  0xA0CC0004  0xA0 0xCC 0x20 0x40 
arr[2]  0xA0CC0008  0xA0 0xCC 0x21 0x28 
      ... 
arr[19]  0xA0CC0014  0xA0 0xCC 0x23 0x10 
      ... 
arr[0][0] 0xA0CC2000  ' ' ' ' ' ' ' ' 
arr[0][4] 0xA0CC2004  ' ' ' ' ' ' ' ' 
arr[0][8] 0xA0CC2008  ' ' ' ' 0x00 0x?? 
      ... 
arr[1][0] 0xA0CC2040  ' ' ' ' ' ' ' ' 
arr[1][4] 0xA0CC2044  ' ' ' ' ' ' ' ' 
arr[1][8] 0xA0CC2048  ' ' ' ' 0x00 0x?? 
      ... 
+1

क्षमा करें मैं एक नौसिखिया हूँ, इसलिए मैं गलत हो सकता हूं, लेकिन आवंटन के बाद पूरी तरह से साफ करने के लिए, आपको स्ट्रिंग्स और फ्री एआर की कुल संख्या के माध्यम से लूप करना होगा [i ] साथ ही पूरे सरणी मुक्त (एआर) को मुक्त करना, क्या यह सही है? या यह सिर्फ 'मुक्त (एआर) के लिए पर्याप्त होगा; '? –

3

एक सूचक dereferencing का मतलब मूल्य सूचक अंक करने तक पहुँचने। उदाहरण के लिए,

char c = 'c'; // This is a primitive value. You cannot dereference it. 
char* p1 = &c; // A pointer to the address of c 
char** p2 = &p1; // A pointer to the address of p1 
/* Now, the following is true: 
*p1 == c, i.e. dereferencing p1 allows us to read from/write to c. 
*p2 == p1 
**p2 == *(*p2) == *p1 = c - dereferencing p2 twice is c, too */ 

कारण है कि आप सी की बजाय ग के लिए सूचक का उपयोग सीधे कि एक सूचक आप 1 से अधिक मूल्य का उपयोग करने की अनुमति देता है। इस उदाहरण लें:

char[4] str; 
char c0 = 'a', c1 = 'b', c3 = 'c', c4 = '\0'; 
str[0] = c0; str[1] = c1; str[2] = c2; str[3] = c3; 
str = "abc"; // Same as the above line 

अब हम दूसरे चरित्र की जरूरत है लगता है। हम इसे c1 के साथ एक्सेस कर सकते हैं। लेकिन जैसा कि आप देख सकते हैं, यह संकेत वास्तव में बोझिल है। इसके अलावा, अगर हम इसे लिखने के बजाय फ़ाइल से स्ट्रिंग पढ़ते हैं, तो हमें जटिल चीजें करना होगा। इसके बजाय, हम सिर्फ लिख

str[1] /* or */ *(str+1) 

नोट पहला तत्व सूचकांक 0, दूसरा 1 है - यही कारण है कि हम 1 यहाँ का उपयोग कर रहे है। char** इसे ग्यारह तक बदल देता है - हमारे पास वर्णों की एक सरणी है। मान लें कि हमारे पास ऐसी सरणी है, चलो इसे input पर कॉल करें, और इसमें सभी तारों की लंबाई जानने की आवश्यकता है। इस तरह हम यह कर देगी:

int lensum(char **input) { 
    int res = 0; 
    while (*input) { // This loops as long as the value input points to is not 0. 
     char* p = *input; // Make a copy of the value input currently points to 
     while (*p != '\0') { // Loop while the copy does not point to a char '\0' 
      res += 1; // We found a character 
      p++; // Check next character in the next iteration 
     } 
     input++; // Check next string in the next iteration 
    } 
    return res; 
} 
+0

यह किस लाइन पर किया जाता है? चार * पी 1 = और सी; ? – jarryd

+0

@alJaree बिल्कुल। सी सी का पता है। – phihag

9

एक सूचक एक प्रकार है कि बजाय वास्तविक मूल्य धारण करने की, एक मूल्य के लिए एक भाषण रखती है।

तो, char * p के मामले में, एक बार आवंटित किए जाने पर, पी में एक पता होगा। डी को संदर्भित करना कि पॉइंटर का मतलब पता ए पर संग्रहीत मान को एक्सेस करना है। कारण आप char * में तारों को स्टोर कर सकते हैं क्योंकि आवंटित स्मृति आवंटित है। तो, ए एक ऐसा पता है जो पहले चरित्र को स्टोर करता है, ए + 1 एक ऐसा पता है जो दूसरे चरित्र को स्टोर करता है और इसी तरह।

चार ** पीपी के मामले में, यह एक चार * के एक पते संग्रहीत करता है। इस पते को कॉल करें बी। इसलिए, डीईफ़्रेंसिंग पीपी का मतलब पता बी पर मूल्य का उपयोग करना है, जो एक char * होता है, जो स्ट्रिंग को पकड़ने के लिए होता है। इसी तरह, बी + 1 (वास्तव में बी + आकार (char *)) अगले मान को स्टोर करता है, जो एक और स्ट्रिंग है।

दो बार कॉन्फ़्रेंसिंग पीपी दो बार (यानी ** पीपी) का मतलब है कि आप पहले बी पर मूल्य का उपयोग कर रहे हैं, उदाहरण के लिए ए है, और उसके बाद यह पता लगाना कि एक बार पता ए पर मूल्य प्राप्त करने के लिए, जो कुछ चरित्र है।

+0

वास्तव में अच्छी व्याख्या। धन्यवाद। – jarryd

3

आरेख एक 1000 शब्दों के लायक हैं। एक नज़र here

चार, चार * और चार ** है बस का वर्णन क्या एक चर (स्मृति के क्षेत्र) शामिल हैं प्रकार के होते हैं।

* चर के रूप में dereferencing का उपयोग करना वास्तव में वैरिएबल में मान को स्मृति पते के रूप में मानने के लिए कहता है और वास्तव में उस पते पर मान वापस कर देता है। यह संकेत है।

** चर केवल संकेत के दो स्तर हैं। यानी चर में मान डेटा के एक और स्मृति पते का एक स्मृति पता है जो वापस किया जाएगा।

पतों आम तौर पर ऑपरेटर, & के पते से या new

+1

धन्यवाद :) 5 और जाने के लिए ..: पी – jarryd

संबंधित मुद्दे