2016-09-14 15 views
10

अंदर काम करता है यह प्रश्न इस पूछे जाने वाले प्रश्न के लिए एक विहित डुप्लीकेट के रूप में इस्तेमाल किया जा करने के लिए है:गतिशील स्मृति पहुँच केवल समारोह

मैं एक समारोह के अंदर गतिशील डेटा का आवंटन कर रहा हूँ और सब कुछ अच्छी तरह से काम करता है, लेकिन केवल समारोह जहां आवंटन के अंदर जगह लेता है। जब मैं फ़ंक्शन के बाहर एक ही डेटा का उपयोग करने का प्रयास करता हूं, तो मुझे क्रैश या अन्य अप्रत्याशित प्रोग्राम व्यवहार मिलता है।

यहाँ एक MCVE:

#include <stdlib.h> 
#include <stdio.h> 

void print_array (int* data, int size) 
{ 
    for(int i=0; i<size; i++) 
    { 
    printf("%d ", data[i]); 
    } 
    printf("\n"); 
} 


void create_array (int* data, int size) 
{ 
    data = malloc(sizeof(*data) * size); 
    for(int i=0; i<size; i++) 
    { 
    data[i] = i; 
    } 

    print_array(data, size); 
} 


int main (void) 
{ 
    int* data; 
    const int size = 5; 

    create_array(data, size); 
    print_array(data, size); // crash here 
} 

जब भी print_arraycreate_array समारोह अंदर से कहा जाता है, मैं उम्मीद उत्पादन 0 1 2 3 4 मिलता है, लेकिन जब मैं main से यह कहते हैं, मैं एक कार्यक्रम दुर्घटना मिलता है।

इसका कारण क्या है?

+3

मैंने आपको इतनी बेवकूफ गलती करने के लिए लगभग नीचे गिरा दिया :) –

+0

@ जीन-फ्रैंकोइसफैबर दुर्भाग्य से मुझे प्रश्न को समुदाय विकी बनाने का कोई तरीका नहीं मिला है, केवल जवाब। मैंने mods poked है, तो उम्मीद है कि यह जल्द ही समुदाय विकी में परिवर्तित हो जाएगा। – Lundin

+2

मुझे लगता है कि प्रलेखन बीटा पर बेहतर होस्ट किया जा सकता है। – LPs

उत्तर

10

इस बग का कारण यह है कि datacreate_array फ़ंक्शन द्वारा उपयोग किया गया एक स्थानीय चर है जो केवल उस फ़ंक्शन के अंदर मौजूद है। malloc से प्राप्त असाइन किया गया मेमोरी पता केवल इस स्थानीय चर में संग्रहीत है और कभी भी कॉलर पर वापस नहीं आया है।


इस सरल उदाहरण पर विचार करें:

void func (int x) 
{ 
    x = 1; 
    printf("%d", x); 
} 

... 
int a; 
func(a); 
printf("%d", a); // bad, undefined behavior - the program might crash or print garbage 

यहाँ, एक चर a की कॉपी समारोह के अंदर स्थानीय रूप से संग्रहीत किया जाता है पैरामीटर x के रूप में,। इसे पास-बाय-वैल्यू के रूप में जाना जाता है।

जब x संशोधित किया गया है, केवल स्थानीय चर बदल जाता है। कॉलर में परिवर्तनीय a अपरिवर्तित बनी हुई है, और चूंकि a प्रारंभ नहीं किया गया है, इसमें "कचरा" होगा और विश्वसनीय रूप से उपयोग नहीं किया जा सकता है।


पॉइंटर्स इस पास-दर-मूल्य नियम के लिए अपवाद नहीं हैं। आपके उदाहरण में, सूचक परिवर्तक data फ़ंक्शन के मान द्वारा पारित किया जाता है। data फ़ंक्शन के अंदर पॉइंटर एक स्थानीय प्रति है और malloc से असाइन किया गया पता कभी भी कॉलर को वापस नहीं भेजा जाता है।

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


दो तरीकों से आप कार्य के रूप में काम करने के लिए संशोधित कर सकते हैं। या तो वापस फोन करने वाले के लिए स्थानीय चर की एक प्रति वापस लौट कर:

int* create_array (int size) 
{ 
    int* data = malloc(sizeof(*data) * size); 
    for(int i=0; i<size; i++) 
    { 
    data[i] = i; 
    } 

    print_array(data, size); 

    return data; 
} 

int main (void) 
{ 
    int* data; 
    const int size = 5; 

    data = create_array(size); 
    print_array(data, size); 
} 

या फोन करने वाले चर करने के लिए फोन करने वाले का सूचक चर को पता गुजर और सीधे लिखना द्वारा:

void create_array (int** data, int size) 
{ 
    int* tmp = malloc(sizeof(*tmp) * size); 
    for(int i=0; i<size; i++) 
    { 
    tmp[i] = i; 
    } 

    *data = tmp;  
    print_array(*data, size); 
} 

int main (void) 
{ 
    int* data; 
    const int size = 5; 

    create_array(&data, size); 
    print_array(data, size); 
} 

या तो प्रपत्र ठीक है ।

+0

बहुत अच्छा सवाल और उत्तर। आप कहते हैं कि सूचक परिवर्तक मूल्य से गुजरता है, जो दिलचस्प है, क्योंकि एक सूचक होने के बाद इसमें एक पता होता है। आपने अपने दूसरे फ़ंक्शन में गलती की है, यह 'print_array (tmp, आकार) होना चाहिए; * डेटा = टीएमपी'। या आप इसके बजाय लिख सकते हैं: '* डेटा = tmp; printArray (* डेटा, आकार); ' –

+0

@ RestlessC0bra धन्यवाद, यह तय किया गया है। हालांकि यह एक समुदाय विकी है, इसलिए आप इसे भी संपादित करने के लिए स्वतंत्र हैं। – Lundin

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