2009-09-09 18 views
23

मेरे पास कुछ अलग-अलग फ़ंक्शंस में कुछ कोड है जो इस तरह कुछ दिखता है:मैं कॉलिंग फ़ंक्शन में मेमोरी आवंटित कैसे कर सकता हूं (इसे पॉइंटर-पैरामीटर के माध्यम से) वापस कर सकता हूं?

void someFunction (int *data) { 
    data = (int *) malloc (sizeof (data)); 
} 

void useData (int *data) { 
    printf ("%p", data); 
} 

int main() { 
    int *data = NULL; 

    someFunction (data); 

    useData (data); 

    return 0; 
} 

someFunction() और useData() अलग मॉड्यूल (* .c फ़ाइलों) में परिभाषित हैं।

समस्या यह है कि, जबकि मॉलोक ठीक काम करता है, और आवंटित स्मृति someFunction में प्रयोग योग्य है, फ़ंक्शन वापस आने के बाद समान स्मृति उपलब्ध नहीं है।

प्रोग्राम का एक उदाहरण रन here देखा जा सकता है, जिसमें आउटपुट विभिन्न मेमोरी पतों को दिखाता है।

क्या कोई मुझे बता सकता है कि मैं यहां क्या कर रहा हूं, और मैं यह कोड कैसे काम कर सकता हूं?


संपादित करें: ऐसा लगता है कि मुझे ऐसा करने के लिए डबल पॉइंटर्स का उपयोग करने की आवश्यकता है - जब मैं वास्तव में डबल पॉइंटर्स का उपयोग करता हूं तो मुझे वही काम करने के बारे में कैसे जाना होगा? तो उदा। डेटा

int **data = NULL; //used for 2D array 

है तो क्या मुझे फ़ंक्शन कॉल में ट्रिपल पॉइंटर्स का उपयोग करने की आवश्यकता है?

+0

हाँ, आप की आवश्यकता होगी ट्रिपल प्वाइंटर्स – vpram86

उत्तर

45

आप एक सूचक-टू-सूचक का उपयोग करना चाहते:

void someFunction (int **data) { 
    *data = malloc (sizeof (int)); 
} 

void useData (int *data) { 
    printf ("%p", data); 
} 

int main() { 
    int *data = NULL; 

    someFunction (&data); 

    useData (data); 

    return 0; 
} 

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

ध्यान दें कि आपके मुख्य के शीर्ष पर समस्या, कोड में एक और बग था: sizeof(data) आपको पॉइंटर को स्टोर करने के लिए आवश्यक बाइट्स की संख्या देता है (32-बिट ओएस पर 4 बाइट्स या 64-बिट ओएस पर 8 बाइट्स), जबकि आप वास्तव में बाइट्स की संख्या चाहते हैं स्टोर करने की आवश्यकता है जो पॉइंटर (int, यानी अधिकांश ओएस पर 4 बाइट्स) को इंगित करता है। क्योंकि आम तौर पर sizeof(int *)>=sizeof(int), यह शायद किसी समस्या का कारण नहीं होता, लेकिन यह कुछ पता होना चाहिए। मैंने उपरोक्त कोड में इसे सही किया है।

यहाँ संकेत करने वाली संकेत पर कुछ उपयोगी प्रश्न हैं:

How do pointer to pointers work in C?

Uses for multiple levels of pointer dereferences?

+2

मैं सुझाव देता हूं कि इसे "डबल पॉइंटर" न कहें - "पॉइंटर टू डबल" के साथ आसानी से उलझन में। – Nefrubyr

+0

"डबल पॉइंटर" और "ट्रिपल पॉइंटर" वास्तव में काफी आम शब्द हैं –

+0

टिप्पणियों के लिए धन्यवाद - भले ही मैं सहमत हूं कि "डबल पॉइंटर" काफी आम है, मैंने इसे भ्रम से बचने के लिए समाप्त कर दिया है। –

4

यदि आप पॉइंटर को संशोधित करना चाहते हैं तो आपको पॉइंटर को पॉइंटर पास करना होगा।

यानी। :

void someFunction (int **data) { 
    *data = malloc (sizeof (int)*ARRAY_SIZE); 
} 

संपादित करें: जोड़ा गया ARRAY_SIZE, कुछ बिंदु पर आप को पता है कि कितने पूर्णांकों आप आवंटित करना चाहते है।

+2

'आकार'' आकार (** डेटा)' होना चाहिए (या बस 'आकार (int) '); यह बग पहले से ही मूल कोड में था। –

+0

malloc के वापसी मूल्य को नहीं डालें - http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?id=1043284351&answer=1047673478 – gnud

+0

दाएं और दाएं, सही। – Ben

2

है ऐसा इसलिए है क्योंकि सूचक डेटा someFunction के लिए मूल्य द्वारा पारित कर दिया है।

int *data = NULL; 
//data is passed by value here. 
someFunction (data); 
//the memory allocated inside someFunction is not available. 

पॉइंटर को पॉइंटर या आवंटित पॉइंटर वापस करने से समस्या हल हो जाएगी।

void someFunction (int **data) { 
    *data = (int *) malloc (sizeof (data)); 
} 


int* someFunction (int *data) { 
    data = (int *) malloc (sizeof (data)); 
return data; 
} 
2

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

int *someFunction() { 
    return (int *) malloc (sizeof (int *)); 
} 

और इसका इस्तेमाल करते हैं:

int *data = someFunction(); 
2

अलावा doublepointer तकनीक का उपयोग कर, हो, तो केवल 1 वापसी परम जरूरत पुनर्लेखन से निम्नलिखित के रूप में है आपके द्वारा आवंटित कुछ अन्य मेमोरी "डेटा == नल" से "डेटा == 0xabcd" तक। इसलिए डेटा को संशोधित करने के लिए आपको डेटा का पता यानी & डेटा पास करना होगा।

void someFunction (int **data) { 
    *data = (int *) malloc (sizeof (int)); 
} 
+0

नहीं, मैंने बस चीजों को सरल बनाने के लिए ऐसा किया - इसे वापस नहीं कर सकता। –

+0

मैं अनुमान लगा रहा था .... लेकिन आप कभी नहीं जानते। ; ^) – Toad

0

यहाँ आप सूचक यानी संशोधित करने की कोशिश कर रहे

0

आपके अतिरिक्त प्रश्न का जवाब दे रहे आप में संपादित:

'*' कुछ करने के लिए एक सूचक को दर्शाता है। तो '**' किसी पॉइंटर को किसी पॉइंटर के लिए पॉइंटर होगा, '***' पॉइंटर को पॉइंटर को किसी पॉइंटर के लिए सूचक, आदि

'int ** डेटा' की सामान्य व्याख्या (यदि डेटा एक फ़ंक्शन पैरामीटर नहीं है) int arrays की सूची में एक सूचक होगा (उदाहरण के लिए 'int a [100] [100]')।

तो आप पहली बार अपने पूर्णांक सरणियों आवंटित करने के लिए आवश्यकता होगी (मैं एक सीधा() सरलता के लिए malloc के लिए कॉल उपयोग कर रहा हूँ):

data = (int**) malloc(arrayCount); //allocate a list of int pointers 
for (int i = 0; i < arrayCount; i++) //assign a list of ints to each int pointer 
    data [i] = (int*) malloc(arrayElemCount); 
0

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

रिटर्न void * इसलिए किसी भी प्रकार के आवंटन के लिए उपयोग किया जा सकता है।

void myAllocator (T **p, size_t count) 
{ 
    *p = malloc(sizeof **p * count); 
} 
... 
void foo(void) 
{ 
    T *p = NULL; 
    myAllocator(&p, 100); 
    ... 
} 

एक अन्य विधि सूचक बनाने के लिए है: यहाँ एक समारोह में स्मृति आवंटन और पैरामीटर के माध्यम से सूचक लौटने के लिए सामान्य पद्धति है

int *data = someFunction (sizeof(int)); 
1

:

void *someFunction (size_t size) { 
    return malloc (size); 
} 

और के रूप में उपयोग फ़ंक्शन का रिटर्न वैल्यू (मेरी पसंदीदा विधि):

T *myAllocator (size_t count) 
{ 
    T *p = malloc(sizeof *p * count); 
    return p; 
} 
... 
void foo(void) 
{ 
    T *p = myAllocator(100); 
    ... 
} 

स्मृति प्रबंधन पर कुछ नोट:

  1. स्मृति प्रबंधन के साथ समस्याओं से बचने के लिए सबसे अच्छा तरीका है स्मृति प्रबंधन से बचने के लिए है, जब तक आप वास्तव में की आवश्यकता नहीं है तब तक गतिशील स्मृति के साथ मक न करें।
  2. malloc() का परिणाम न डालें जब तक कि आप 1 9 8 9 एएनएसआई मानक की भविष्यवाणी करने वाले कार्यान्वयन का उपयोग नहीं कर रहे हैं या आप कोड को C++ के रूप में संकलित करना चाहते हैं। यदि आप stdlib.h को शामिल करना भूल जाते हैं या अन्यथा स्कोप में malloc() के लिए प्रोटोटाइप नहीं है, तो वापसी मूल्य कास्टिंग एक मूल्यवान कंपाइलर डायग्नोस्टिक को दबाएगा।
  3. डेटा प्रकार के आकार (i.e., sizeof *psizeof (T) के बजाय आवंटित ऑब्जेक्ट का आकार का उपयोग करें); डेटा प्रकार को बदलने के लिए यह आपको कुछ दिल की धड़कन बचाएगा (int से long या float to double) कहें। यह कोड को थोड़ा बेहतर आईएमओ भी पढ़ता है।
  4. उच्च स्तरीय आवंटन और कार्यों को रद्द करने के पीछे स्मृति प्रबंधन कार्यों को अलग करें; ये न केवल आवंटन बल्कि प्रारंभिकरण और त्रुटियों को भी संभाल सकते हैं।
+0

डबल-अप्रत्यक्ष सूचक दृष्टिकोण का एक लाभ यह है कि यह पास/असफल होने से स्थिति की स्थिति वापस कर सकता है, और यदि वे वैध नहीं होते हैं तो पॉइंटर्स हमेशा 'शून्य' होते हैं, तो यह "आवश्यक होने पर आवंटित" लागू कर सकते हैं। दुर्भाग्यवश, यहां तक ​​कि प्लेटफार्मों पर भी जहां सभी पॉइंटर्स के समान प्रतिनिधित्व कोड होते हैं, उन्हें उलझाने वाले कंप्यूटर्स को एलियासिंग द्वारा ट्रिप किए जाने से रोकने के लिए बदसूरत 'मॉलोक' कॉल का उपयोग करने की आवश्यकता होगी (एक सेन कंपाइलर को यह समझना चाहिए कि 'कुछ ऐसा करने वाला कॉल ((शून्य **) और पीआरटी) 'पीआरटी को संशोधित करने की संभावना है) भले ही 'ptr'' void * 'के अलावा कुछ और हो)। – supercat

7

एक आम ख़तरा खासकर यदि आप सेल्सियस के लिए प्रपत्र जावा ले जाया गया/C++

याद है जब आप एक सूचक गुजर, यह मूल्य द्वारा पारित है यानी सूचक का मूल्य की नकल की है। पॉइंटर द्वारा इंगित डेटा में परिवर्तन करने के लिए यह अच्छा है लेकिन पॉइंटर में कोई भी परिवर्तन सिर्फ एक प्रतिलिपि के बाद ही स्थानीय है !!

चाल के बाद से आप इसे बदल करना चाहते हैं संदर्भ द्वारा सूचक पारित उपयोग करने के लिए है यानी malloc यह आदि

** सूचक -> एक noobie सी प्रोग्रामर को डराने जाएगा;)

+0

हैलो, मुझे "मूल्य से गुजरना" भाग समझ में नहीं आता है। एक सूचक एक एड्रेस सही है? इसलिए जब आप फ़ंक्शन में कोई पता देते हैं तो यह एक प्रतिलिपि कैसे हो सकता है? – hadesMM

+3

एक सूचक एक प्रकार का है जिसका मूल्य एक स्मृति पता है। हम स्मृति में अन्य वस्तुओं को इंगित करने के लिए इस सूचक प्रकार का उपयोग करते हैं। मान लें कि आप किसी फ़ंक्शन में पॉइंटर पी {वैल: 0x1234} पास करते हैं। (याद रखें पॉइंटर्स ऑब्जेक्ट्स भी हैं, इसलिए उनके पास एक पता भी है, 0x8888 कहें) - फ़ंक्शन पॉइंटर प्राप्त करेगा और ऑब्जेक्ट को 0x1234 पर एक्सेस करने में सक्षम होगा, हालांकि इस पते पर इंगित पॉइंटर पॉइंटर के समान सूचक नहीं है 0x8888, यह एक प्रति है और सिर्फ वही मूल्य है! - यह मूल्य से एक int गुजरने के समान है। यह कॉपी हो गया है। –

+0

ओह यह बहुत अधिक स्पष्ट है आपको बहुत धन्यवाद! – hadesMM

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

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