2012-09-12 21 views
11

मैं सी के साथ शुरुआत कर रहा हूँ और मैं अपने दम पर सीख रहा हूँ "त्रुटि समारोह स्थानीय चर का पता देता है"। मैं निम्नलिखित समारोह बनाने हूँ:सी:

char *foo(int x){ 
    if(x < 0){ 
     char a[1000]; 
     char b = "blah"; 
     x = x - 1; 
     char *c = foo(x); 
     strcpy(a, b); 
     strcat(a, c); 
     return a; 
     } 
    blah ... 
} 

मैं मूल रूप से एक साथ जोड़ दिया स्ट्रिंग वापस जाने के लिए कोशिश कर रहा हूँ, लेकिन मैं निम्नलिखित त्रुटि मिलती है:

"त्रुटि: फ़ंक्शन स्थानीय चर का पता", किसी भी सुझाव, इसे कैसे ठीक करें?

+0

के संभावित डुप्लिकेट [सी चेतावनी: समारोह रिटर्न स्थानीय चर का पता] (http://stackoverflow.com/questions/6897914/c-चेतावनी-फ़ंक्शन-रिटर्न-पता-स्थानीय-परिवर्तनीय) – netcoder

+0

जब आप अपना प्रश्न लिखते हैं, तो यह इसके आधार पर कुछ डुप्लिकेट सुझाता है। आपको शायद उनको जांचना चाहिए था। – netcoder

+0

मुझे लगता है कि यह है कि यह सहायक हो सकता है http://stackoverflow.com/a/6897993 –

उत्तर

1

a समारोह में स्थानीय रूप से परिभाषित किया गया है, और समारोह के बाहर नहीं किया जा सकता। और लौट आए सूचक पर कुछ बिंदु कॉल free पर

char *a = malloc(1000); 

: आप समारोह से एक char सरणी वापस करना चाहते हैं, तो आप यह गतिशील आवंटित करने के लिए की आवश्यकता होगी।

आपको इस लाइन पर एक चेतावनी भी दिखाई देनी चाहिए: char b = "blah";: आप char पर एक स्ट्रिंग अक्षर निर्दिष्ट करने का प्रयास कर रहे हैं।

2

a फ़ंक्शन के लिए एक सरणी स्थानीय है। फ़ंक्शन लौटने के बाद यह अब मौजूद नहीं है और इसलिए आपको स्थानीय चर के पते को वापस नहीं करना चाहिए।
दूसरे शब्दों में जीवन a की समारोह के दायरे ({, }) के भीतर है और यदि आप इसे करने के लिए एक सूचक लौट क्या आपके पास कुछ स्मृति जो मान्य नहीं है करने के लिए एक सूचक की ओर इशारा करते है। इस तरह के चर भी स्वचालित variabels कहा जाता है क्योंकि उनके जीवनकाल स्वचालित रूप से आप यह स्पष्ट रूप से प्रबंधन करने के लिए की जरूरत नहीं है किया जाता है।

जब से तुम समारोह आप आप ढेर पर एक सरणी का आवंटन और इसे करने के लिए एक सूचक वापस जाने के लिए की जरूरत के दायरे से बाहर करने के लिए जारी रहती है चर का विस्तार करने की जरूरत है।

char *a = malloc(1000); 

इस तरह सरणी a स्मृति में रहता तक आप एक ही पते पर एक free() कहते हैं।
ऐसा करने के लिए मत भूलना या आप एक मेमोरी रिसाव के साथ खत्म हो जाते हैं।

28

स्थानीय चर एक जीवन भर जो केवल ब्लॉक जिसमें यह परिभाषित किया गया है के अंदर फैली है। जिस क्षण वह नियंत्रण करता है उस ब्लॉक के बाहर जाता है जिसमें स्थानीय चर परिभाषित किया जाता है, चर के लिए भंडारण अब आवंटित नहीं किया जाता है (गारंटी नहीं है)। इसलिए चर के जीवनकाल क्षेत्र के बाहर चर के स्मृति पते का उपयोग अपरिभाषित व्यवहार होगा। बजे, वहाँ

दूसरी ओर आप निम्न कर सकते पर।

char *str_to_ret = malloc (sizeof (char) * required_size); 
    . 
    . 
    . 
return str_to_ret; 

और इसके बजाय str_to_ret का उपयोग करें। और जब return आईएनजी str_to_ret, malloc द्वारा आवंटित पता वापस कर दिया जाएगा। malloc द्वारा आवंटित स्मृति को ढेर से आवंटित किया गया है, जिसमें जीवन भर है जो कार्यक्रम के पूरे निष्पादन को फैलाता है। इसलिए आप किसी भी ब्लॉक से स्मृति स्थान तक पहुंच सकते हैं और प्रोग्राम चलने के दौरान किसी भी समय।

यह भी ध्यान रखें कि यह आवंटित स्मृति ब्लॉक, free मेमोरी लीक से बचाने के लिए एक अच्छा अभ्यास है। एक बार जब आप स्मृति मुक्त कर लेंगे, तो आप उस ब्लॉक को फिर से एक्सेस नहीं कर सकते।

+0

साइटनोट: समाधान में Encapsulation/लाइफटाइम/जिम्मेदारी डिजाइन-दोष: कॉलर एक मॉलोक शुरू करता है - लेकिन CALLED को इसे मुक्त करना होता है। इसके अलावा यदि आप फ़ंक्शन को दिए गए मानों को sanitize/चेक नहीं करते हैं तो आप आसानी से ढेर में एक बड़े पैमाने पर बड़े ब्लॉक को मॉलोक कर सकते हैं ... – Gewure

+0

किसी ऑब्जेक्ट के जीवनकाल को समझाने के लिए बस एक उदाहरण। – phoxis

3

यह पंक्ति:

char b = "blah"; 

अच्छा नहीं है - अपने lvalue एक सूचक की जरूरत है।

आपका कोड स्टैक ओवरफ़्लो के खतरे में भी है, क्योंकि आपकी रिकर्सन जांच x के घटते मूल्य को बाध्य नहीं कर रही है।

वैसे भी, वास्तविक त्रुटि संदेश जो आप प्राप्त कर रहे हैं क्योंकि char a एक स्वचालित चर है; पल आप return यह अस्तित्व में रहेगा। आपको एक स्वचालित चर के अलावा कुछ और चाहिए।

-1
char b = "blah"; 

होना चाहिए:

char *b = "blah"; 
+0

इससे कोई फर्क नहीं पड़ता। मेरा जवाब पढ़ें क्यों! – Gewure

2

अभ्यास:

मैं वर्तमान में मेरा एक दोस्त सी की बुनियादी अवधारणाओं शिक्षण रहा हूँ - और यह बहुत ही सरल और सीधी-सपाट के साथ आया था (मुझे उम्मीद है) कोड उदाहरण जो मूल रूप से सबकुछ बताता है। आप लोगों से इसे छिपाना नहीं चाहते थे! :)

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

/* function header definitions */ 
char* getString();      //<- with malloc (good practice) 
char * getStringNoMalloc(); //<- without malloc (fails! don't do this!) 
void getStringCallByRef(char* reference); //<- callbyref (good practice) 

/* the main */ 
int main(int argc, char*argv[]) { 

    //######### calling with malloc 
    char * a = getString(); 
    printf("MALLOC### a = %s \n", a); 
    free(a); 

    //######### calling without malloc 
    char * b = getStringNoMalloc(); 
    printf("NO MALLOC### b = %s \n", b); //this doesnt work, question to yourself: WHY? 
    //HINT: the warning says that a local reference is returned. ??! 
    //NO free here! 

    //######### call-by-reference 
    char c[100]; 
    getStringCallByRef(c); 
    printf("CALLBYREF ### c = %s \n", c); 

    return 0; 
} 

//WITH malloc 
char* getString() { 

    char * string; 
    string = malloc(sizeof(char)*100); 

    strcat(string, "bla"); 
    strcat(string, "/"); 
    strcat(string, "blub"); 

    printf("string : '%s'\n", string); 

    return string; 
} 

//WITHOUT malloc (watch how it does not work this time) 
char* getStringNoMalloc() { 

    char string[100] = {}; 

    strcat(string, "bla"); 
    strcat(string, "/"); 
    strcat(string, "blub"); 
    //INSIDE this function "string" is OK 
    printf("string : '%s'\n", string); 

    return string; //but after returning.. it is NULL? :) 
} 

// ..and the call-by-reference way to do it (prefered) 
void getStringCallByRef(char* reference) { 

    strcat(reference, "bla"); 
    strcat(reference, "/"); 
    strcat(reference, "blub"); 
    //INSIDE this function "string" is OK 
    printf("string : '%s'\n", reference); 
    //OUTSIDE it is also OK because we hand over a reference defined in MAIN 
    // and not defined in this scope (local), which is destroyed after the function finished 
} 

जब यह संकलन, आप [इरादा] चेतावनी मिलती है:

[email protected]:~$ gcc -o example.o example.c 
example.c: In function ‘getStringNoMalloc’: 
example.c:58:16: warning: function returns address of local variable [-Wreturn-local-addr] 
     return string; //but after returning.. it is NULL? :) 
      ^~~~~~ 

... मूल रूप से हम यहाँ चर्चा कर रहे हैं!

मेरी उदाहरण चल रहा यह उत्पादन पैदावार:

[email protected]:~$ ./example.o 
string : 'bla/blub' 
MALLOC### a = bla/blub 
string : 'bla/blub' 
NO MALLOC### b = (null) 
string : 'bla/blub' 
CALLBYREF ### c = bla/blub 

सिद्धांत:

इस उपयोगकर्ता @phoxis से बहुत अच्छी तरह से जवाब दिया गया है। मूल रूप से इसके बारे में सोचो इस तरह से: सब कुछ inbetween { और }स्थानीय गुंजाइश है, इस प्रकार सी स्टैंडर्ड कर रहा है बाहर "अनिर्धारित" है। मॉलोक का उपयोग करके आप HEAP (प्रोग्राम स्कोप) से स्मृति लेते हैं और STACK (फ़ंक्शन स्कोप) से नहीं - इस प्रकार यह बाहर से 'दृश्यमान' है। ऐसा करने का दूसरा सही तरीका कॉल-बाय-रेफरेंस है। यहां आप पैरेंट-स्कोप के अंदर var को परिभाषित करते हैं, इस प्रकार यह स्टैक का उपयोग कर रहा है (क्योंकि मूल दायरा मुख्य() है)।

सारांश:

3 यह करने के लिए तरीके, उनमें से एक झूठी। सी एक फंक्शंस के लिए एक गतिशीलता आकार स्ट्रिंग वापस करने के लिए बेकार है। या तो आपको इसे मॉलोक करना होगा और फिर इसे मुक्त करना होगा, या आपको कॉल-बाय-रेफरेंस करना होगा। या सी ++ का उपयोग करें;)

1

न तो मॉलोक या संदर्भ द्वारा कॉल की आवश्यकता है।आप फ़ंक्शन के भीतर एक पॉइंटर घोषित कर सकते हैं और इसे उस स्ट्रिंग/सरणी पर सेट कर सकते हैं जिसे आप वापस करना चाहते हैं।

@ आधार के रूप में Gewure के कोड का उपयोग करना: पूरी तरह से

char *getStringNoMalloc(void){ 
    char string[100] = {}; 
    char *s_ptr = string; 

    strcat(string, "bla"); 
    strcat(string, "/"); 
    strcat(string, "blub"); 
    //INSIDE this function "string" is OK 
    printf("string : '%s'\n", string); 

    return s_ptr; 
} 

काम करता है।

मूल प्रश्न में कोड का एक गैर-पाश संस्करण के साथ

:

char *foo(int x){  
    char a[1000]; 
    char *a_ptr = a; 
    char *b = "blah";  

    strcpy(a, b); 

    return a_ptr; 
}