2013-01-17 32 views
13

से नीचे लौटें * नीचे 3 कार्य हैं। मुख्य() प्रिंट के रूप में प्रिंट आउट। अब, mycharstack() में स्ट्रिंग को स्टैक पर संग्रहीत किया जाता है, इसलिए "ch" गुंजाइश से बाहर हो जाता है, यह स्ट्रिंग को वापस करने में सक्षम नहीं होना चाहिए। यह सही तरीके से कैसे काम करता है? मुझे लगता है कि mychar() में संग्रहीत स्ट्रिंग भी ढेर पर है। क्या यह सही ढंग से काम करना चाहिए? मुझे लगता है कि कोड और मेमोरी लीक में अन्य त्रुटियां हैं, कृपया मुझे बताएं अगर कोई है। मैं std :: स्ट्रिंग के साथ इन क्लीनर & को आसान कर सकता था। लेकिन मैं समझना चाहता हूं कि char * के साथ क्या चल रहा है।फ़ंक्शन

#include <iostream> 
using namespace std; 

char* mychar() 
{ 
    return "Hello"; 
} 

char* mycharstack() 
{ 
    char* ch = "Hello Stack"; 
    return ch; 
} 

char* mycharheap() 
{ 
    char* ch = new char; 
    ch = "Hello Heap"; 
    return ch; 
} 

int main() 
{ 
    cout << "mychar() = " << mychar() << endl; 
    cout << "mycharstack() = " << mycharstack() << endl; 
    cout << "mycharheap() = " << mycharheap() << endl; 

    system("PAUSE"); 
    return 0; 
} 

उत्तर

15

सी ++ में, स्ट्रिंग हैंडलिंग, से उदाहरण के लिए, पास्कल अलग है।

char* mycharheap() 
{ 
    char* ch = new char; 
    ch = "Hello Heap"; 
    return ch; 
} 

यह निम्नलिखित है:

  1. char* ch = new char; एक चरित्र के लिए स्मृति बनाता है, और चर ch
  2. ch = "Hello Heap"; करने के लिए इसे प्रदान करती है स्मृति, जो बाइट्स "Hello Heap\0" शामिल केवल पढ़ने के लिए चर ch सूचक को प्रदान करती है। साथ ही, परिवर्तनीय ch की मूल सामग्री खो जाती है, जिसके परिणामस्वरूप स्मृति रिसाव होता है।
  3. return ch; चर ch को संग्रहीत सूचक देता है।

क्या आप शायद चाहता था है

char* mycharheap() 
{ 
    char* ch = new char[11] /* 11 = len of Hello Heap + 1 char for \0*/; 
    strcpy(ch, "Hello Heap"); 
    return ch; 
} 

नोट strcpy -> आप ch में स्मृति, 11 वर्ण के लिए स्थान है कि मिल गया है, और आप केवल पठन-भाग से स्ट्रिंग द्वारा यह भरने कर रहे हैं स्मृति की

इस मामले में एक रिसाव नहीं किया जाएगा। आप की तरह, लेखन के बाद स्मृति को हटाना होगा:

char* tempFromHeap = mycharheap(); 
cout << "mycharheap() = " << tempFromHeap << endl; 
delete[] tempFromHeap; 

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

क्या अपरिभाषित व्यवहार में परिणाम होगा पीछा कर रहा है:

char* mycharstack() 
{ 
    char[] ch = "Hello Heap"; /* this is a shortcut for char[11] ch; ch[0] = 'H', ch[1] = 'e', ...... */ 
    return ch; 
} 

यह बाइट्स "Hello Heap\0" साथ ढेर पर सरणी पैदा करेगा, और फिर उस सरणी के पहले बाइट के लिए सूचक वापस जाने के लिए कोशिश करता है (जो कर सकते हैं, फ़ंक्शन को कॉल में, कुछ भी करने के लिए बिंदु)

+0

यदि मैंने अपने कोड में उल्लिखित एक के साथ mycharheap() को प्रतिस्थापित किया है, अभी भी रिसाव होगा ... सही? मुख्य() आवंटित स्मृति को मुक्त करने वाले कोई भी नहीं। – ontherocks

+0

हां। मेरा अद्यतन उत्तर देखें। – nothrow

+0

तो mycharheap() जैसे कार्यों के लिए, यह अन्य कार्यों में पैरामीटर के रूप में सीधे इसका उपयोग करने की अनुशंसा नहीं करता है जो इनपुट पैरामीटर के रूप में char * लेते हैं। उदाहरण के लिए कहें कि एक फ़ंक्शन 'प्रिंट (char * char_in) है;' मुझे कुछ प्रिंट नहीं करना चाहिए जैसे 'प्रिंट (mycharheap()); '। इससे स्मृति रिसाव हो जाएगा। क्या मैं सही हू? – ontherocks

0

समारोह mycharheap() लीक कर रहा है: यदि आप एक char ढेर पर आवंटित की लंबाई की एक स्मृति क्षेत्र के लिए अपने सूचक बिंदु बनाने, और फिर आपको लगता है कि सूचक एक स्ट्रिंग शाब्दिक जो पढ़ा में संग्रहित है को इंगित करने के संशोधित केवल स्मृति आवंटित स्मृति को मुक्त नहीं किया जाएगा।

+0

मैं आवंटित स्मृति कैसे मुक्त करूं? मेरा मतलब है, मैं उपरोक्त कोड में कहां से कॉल करूँ? – ontherocks

+0

@ontherocks: यह सवाल गलत है ;-) आपको पॉइंटर को पहले स्थान पर पुन: असाइन नहीं करना चाहिए। यदि आप ढेर पर "हैलो वर्ल्ड" स्ट्रिंग आवंटित करना चाहते हैं, तो पर्याप्त लंबाई ('नया चार [आकार]') का बफर आवंटित करें और फिर स्ट्रिंग को उस बफर में कॉपी करें। एक बार जब आप कॉलर को पॉइंटर वापस कर देते हैं, तो इसे कॉल करने की कॉलर की ज़िम्मेदारी है (परिणाम को 'char * 'पॉइंटर को सौंपकर और –

+0

के बाद उस पॉइंटर पर' डिलीट 'को कॉल करके, ऊपर दिए गए कोड में खाली करने का कोई तरीका नहीं है आवंटित स्मृति? – ontherocks

1

अपने कोड सिर्फ एक लीक char में कोई त्रुटियां नहीं हैं। लेकिन यह बहुत अजीब है।

char* mycharheap() 
{ 
    char* ch = new char; //creates a pointer that points to a new char in the heap 
    ch = "Hello Heap"; //overwrites the pointer with const char - but this cast is legal. 
         //note: pointer to the previous char is lost 
    return ch;   //return the pointer to the constant area where "Hello heap" is stored. 
         //no, "Hello heap" is not on the heap. 
} 

"आप क्या चाहते हैं:" भाग के लिए, योसियन मेरे से तेज़ था।

+0

तो यह कोड जो बिना किसी त्रुटि के काम करता है, समान नहीं है यदि समान 'char * mycharheap() { char * ch = new char []; ch = "हैलो हीप "; रिटर्न ch; }' – ontherocks

+0

हां। लगभग इंडेंटिकल और उनके पास एक ही समस्या है - "हैलो हीप" 'ढेर पर नहीं है। आप जो चाहते थे उसे कार्यान्वित करने के तरीके को देखने के लिए @ योसीरियन का जवाब देखें। – Csq

1

सबसे पहले, आप सी ++ उपयोग कर रहे हैं, std::string का उपयोग तार प्रतिनिधित्व करने के लिए।

अब आपके प्रश्न पर। char*char (या char एस की सरणी) के लिए एक सूचक है। स्ट्रिंग अक्षर (उद्धरणों में सामान) char के प्रकार सरणी के केवल-पढ़ने वाले ऑब्जेक्ट्स हैं, जो कुछ प्रकार की केवल-पढ़ने वाली स्मृति (न तो ढेर या ढेर पर) में संग्रहीत हैं।

char* के रूप में एक सूचक, बताए में सूचक को परिवर्तित करता है। तो mychar() और mycharstack() दोनों केवल एकमात्र मेमोरी में संग्रहीत एक स्ट्रिंग अक्षर के लिए एक सूचक लौटाते हैं।

mycharheap() बस लीक। आप new char का उपयोग करके ढेर पर एक char आवंटित करते हैं, और फिर इसके पते को भूल जाते हैं और इसके बजाय एक स्ट्रिंग अक्षर पर पॉइंटर लौटाते हैं। मुझे लगता है कि आप इस का मतलब:

char* mycharheap() { 
    char* ch = new char[strlen("Hello Heap") + 1]; 
    strcpy(ch, "Hello Heap"); 
    return ch; 
} 

फिर भी, फिर से पुनरावृति करने के लिए, char* स्ट्रिंग्स के लिए सी में उपयोग नहीं करते हैं ++। std::string का प्रयोग करें।

+0

क्या होगा यदि हमारे पास निम्न है: SET_ERROR_MESSAGE (झूठी, (returnErrorCppString()। C_str()); जहां पूंजी पत्र एक मैक्रो का प्रतिनिधित्व करते हैं जो varargs लेता है। – Zingam

+0

@ ज़िंगम उम्म, क्या? यह किसी भी तरह से प्रश्न या मेरे उत्तर से कैसे संबंधित है? क्या आप विस्तार से समझा सकते हैं? – Angew

+0

ठीक है, SET_ERROR_MESSAGE कॉन्स char * स्वीकार करता है लेकिन आपकी सलाह के अनुसार मैं एक फ़ंक्शन का उपयोग करता हूं जो std :: स्ट्रिंग देता है, फिर मुझे इसका उपयोग करने में सक्षम होने के लिए इसे कॉन्स्ट char * में परिवर्तित करने की आवश्यकता होती है। SET_ERROR_MESSAGE को तृतीय पक्ष लाइब्रेरी द्वारा परिभाषित किया गया है। – Zingam

2

mycharstack में() स्ट्रिंग को लगता है कि स्टैक पर संग्रहीत किया जाता है, इसलिए "ch" गुंजाइश से बाहर हो जाता है, यह स्ट्रिंग को वापस करने में सक्षम नहीं होना चाहिए। यह सही तरीके से कैसे काम करता है?

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

मुझे लगता है कि mychar() में संग्रहीत स्ट्रिंग भी ढेर पर है।

स्ट्रिंग (वर्ण सरणी) स्थिर स्मृति में संग्रहीत है। char* सिर्फ एक पॉइंटर प्रकार है जिसका उपयोग आप आसपास के पते को पार करने के लिए कर सकते हैं। const भी गायब है।

मुझे लगता है कि कोड और मेमोरी लीक में अन्य त्रुटियां हैं, कृपया मुझे बताएं अगर कोई है।

रिसाव अपने तीसरे समारोह में है। आप ढेर पर केवल एक वर्ण के लिए स्मृति आवंटित करते हैं और अपना पता ch नामक चर में संग्रहीत करते हैं। निम्नलिखित असाइनमेंट के साथ आप स्ट्रिंग अक्षर के पते के साथ इस पते को ओवरराइट करते हैं। तो, आप स्मृति लीक कर रहे हैं।

आप स्ट्रिंग चर के लिए प्रकार के रूप में char* के बारे में सोच कर रहे हैं। लेकिन यह नहीं है। यह एक चरित्र या चरित्र अनुक्रम के लिए एक सूचक के लिए प्रकार है।पॉइंटर और स्ट्रिंग जो इंगित कर सकती है वह दो अलग-अलग चीजें हैं। आपको शायद यहां क्या उपयोग करना चाहिए, इसके बजाय std :: string है।

0

नीचे दिया गया उदाहरण एक प्रश्न था जो तब आया जब मैं फ़ंक्शन कॉल से जानकारी को बाहर खींचने की कोशिश कर रहा था।

#include <iostream> 
#include <cstring> 
using namespace std; 

char* Xout(char* message); 

int main() 
{ 
const int LEN = 64; 
char message[LEN], *x; 

cin>>message; 

x=Xout(message); 
cout<<x; 
return 0; 
} 

char* Xout(char* message) 
{ 
int length=strlen(message); 
for(int i = 0; i < length; i++) 
{ 
    message[i] = 'X'; 
} 
return message; 
}