मैं चार पॉइंटर्स की अवधारणा से थोड़ा भ्रमित था इसलिए मैंने उपयोगकर्ता (मुझे) द्वारा प्रदान किए गए मेरे नाम को प्रिंट करते हुए एक साधारण कोड बनाया। मैं मॉलोक का भी अभ्यास करना चाहता था इसलिए मैंने रैम में एक निश्चित मेमोरी के लिए पॉइंटर को संदर्भित किया, लेकिन मुझे वास्तव में नहीं पता था कि "आकार (चार) *" के बाद क्या रखा जाए क्योंकि वह उपयोगकर्ता इनपुट है, जो अभी तक तय नहीं हुआ है। साथ ही, ऐसा करने के बाद, मैंने स्मृति को मुक्त कर दिया, लेकिन मुझे कमांड लाइन पर एक त्रुटि संदेश मिला:
*** Error in `./char': double free or corruption (fasttop): 0x00000000017fe030 ***
Aborted
ऐसा लगता है कि मैंने एक ही मेमोरी को दो बार या कुछ और मुक्त किया, लेकिन मुझे नहीं पता कि क्या हटाना या जोड़ना है। कृपया सहायता कीजिए!
#include <stdio.h>
#include <cs50.h>
int main (void)
{
char *strings = malloc(sizeof(char) * 10);
printf("What is your name?\n");
//wait for use to type his/her name
strings = get_string();
printf("Hello %s\n", strings);
free (strings);
return 0;
}
5 जवाब
समस्या यह है कि आपका get_strings
आपके प्रारंभिक malloc
को ओवरराइड करता है। एक सूचक मान एक मान है। इसे किसी और चीज़ से जोड़कर, आपने अपने malloc
मान को प्रतिस्थापित कर दिया है।
सबसे पहले आपने एक गतिशील मेमोरी बनाई है जो *strings द्वारा इंगित की जाएगी। लेकिन फिर आप *strings पॉइंटर का उपयोग करके स्थानीय स्ट्रिंग (get_string() फ़ंक्शन से) की ओर इशारा कर रहे हैं। जब आप मुफ्त कॉल करते हैं, तो प्रोग्राम स्थानीय (स्टैक) संदर्भ को हटाने और त्रुटि फेंकने का प्रयास कर रहा है।
उस त्रुटि को हल करने के लिए, प्रोग्राम होना चाहिए
#include <stdio.h>
#include <cs50.h>
int main (void)
{
char *strings = malloc(sizeof(char) * 10);
printf("What is your name?\n");
//wait for use to type his/her name
strcpy(strings, get_string()); // Use strcpy instead of assigning
printf("Hello %s\n", strings);
free (strings);
return 0;
}
char *strings;
- नए मॉलोक की कोई आवश्यकता नहीं है क्योंकि get_string() फ़ंक्शन से लौटाई गई स्ट्रिंग पहले से ही ढेर पर है, आपको केवल पहले वर्ण के लिए पॉइंटर लेने की आवश्यकता है। (get_string() फ़ंक्शन संदर्भ)
स्ट्रिंग्स = get_string ();
प्रिंटफ ("हैलो% s \ n", स्ट्रिंग्स);
- स्ट्रिंग को प्रिंट करने के बाद, आपको इसके लिए आवंटित मेमोरी को मुक्त करना चाहिए, जैसा कि get_string () फ़ंक्शन संदर्भ में बताया गया है
ढेर पर स्टोर स्ट्रिंग (मॉलोक के माध्यम से); मेमोरी को रिसाव से बचने के लिए कॉलर द्वारा मुक्त किया जाना चाहिए।
मुझे लगता है कि बाकी सब ठीक है, इस कोड को आजमाएं:
#include <stdio.h>
#include <cs50.h>
int main (void)
{
char *strings;
printf("What is your name?\n");
//wait for use to type his/her name
strings = get_string();
printf("Hello %s\n", strings);
free (strings);
return 0;
}
आप get_string()
के लिए कोड शामिल नहीं करते हैं, लेकिन आप strings
को इसके रिटर्न वैल्यू के साथ ओवरराइट कर रहे हैं जो गलत है। आप जिस पते को free()
को भेजते हैं, वह malloc()
से आना चाहिए, और ऐसा लगता है कि आप उसका उल्लंघन कर रहे हैं (आपके 10 बाइट्स के लिए लौटाया गया मूल पता खोने के अलावा)।
मान लें कि get_string()
स्थिर संग्रहण लौटाता है (अर्थात आपको इसे मुक्त करने की आवश्यकता नहीं है) आप malloc()
को शामिल किए बिना ऐसा कर सकते हैं।
अगर आप वाकई चाहते हैं, तो ऐसा कुछ काम कर सकता है:
printf("What is your name?\n");
const char *name = get_string();
const size_t nlen = strlen(name);
char * const name_copy = malloc(nlen + 1);
if(name_copy != NULL)
{
memcpy(name_copy, name, nlen + 1);
printf("Hello %s (from my own memory!)\n", name_copy);
free(name_copy);
}
यह बल्कि जटिल है लेकिन आपको यह विचार मिलता है।
लाइन strings = get_string();
वास्तव में get_string()
द्वारा strings
को लौटाया गया मान निर्दिष्ट करती है। यह आपके द्वारा आवंटित स्मृति में नहीं लिखता है।
तो malloc()
द्वारा लौटाया गया मान अधिलेखित कर दिया गया है (और इस मामले में खो गया है)।
free(strings)
जो कुछ भी get_string()
लौटा, उसे जारी कर रहा है। प्रश्न इसके लिए कोड प्रदान नहीं करता है, लेकिन संभवतः यह free()
के लिए मान्य नहीं है।
चूंकि रन-टाइम ने आपको बताया था कि इसे दो बार मुक्त किया गया था, मुझे लगता है कि आपने get_string()
में स्मृति आवंटित की है, फिर इसे मुक्त कर दिया और एक अमान्य सूचक वापस कर दिया।
यदि आप अपने द्वारा आवंटित मेमोरी का उपयोग करना चाहते हैं, तो आपको पॉइंटर स्वीकार करने के लिए get_string()
बदलने की आवश्यकता है:
void get_string(char *str){
//Do whatever writing you value into str[] as an array of char..
}
अच्छा अभ्यास होगा:
void get_string(char *str, size_t max){
//Do whatever writing you value into str[] as an array of char..
//Use max to avoid writing beyond the end of the space allocated...
}
फिर get_string(strings,10);
पर कॉल करें।
संपादित करें: कुछ शोध के बाद दोष की पहचान की गई है। get_string()
सीधे free()
स्ट्रिंग को वापस नहीं करता है, लेकिन इसे पुस्तकालय द्वारा किए गए आवंटन की सूची में जोड़ता है जो बाहर निकलने पर मुक्त हो जाते हैं (teardown()
नामक फ़ंक्शन में atexit()
या अन्य कंपाइलर निर्भर विशेषताएं)।
यह खराब डिज़ाइन है क्योंकि उपभोक्ता कोड को स्मृति को मुक्त करने का कोई सुरक्षित तरीका प्रदान नहीं किया जाता है, जो कि सामान्य उपयोग के मामले में पूरे एप्लिकेशन निष्पादन के लिए आवश्यक नहीं होगा। get_double()
बदतर है क्योंकि यह आवंटित डेटा कभी नहीं लौटाता है लेकिन कभी भी इसका पुन: उपयोग नहीं करता है और सीधे स्मृति रिसाव की मात्रा में होता है।
कोड या तो होना चाहिए:
- दस्तावेज़ीकरण के अनुरूप और
free()
स्ट्रिंग के लिए उपभोक्ता कोड की आवश्यकता है (शायद स्पष्टता के लिए इसका नाम बदलकरget_string_alloc()
करें)। - स्ट्रिंग (
get_new_string()
औरrelease_string()
) को मुक्त करने के लिए लाइब्रेरी रूटीन की पेशकश करें
सी में आवंटित स्मृति के स्वामित्व को स्थानांतरित करने का कोई बहुत अच्छा तरीका नहीं है लेकिन शेष निष्पादन के लिए इसे पकड़ना निश्चित रूप से उत्तर नहीं है। कई पुस्तकालय उपभोक्ता कोड पर आवंटन को आगे बढ़ाने के लिए घरों के चक्कर लगाते हैं, लेकिन यह तब कठिन होता है जब आवश्यक स्थान के पूर्ण आकार को यहां नहीं जाना जा सकता है।
मैं किसी भी फ़ंक्शन के अंत में _alloc()
डालने का सुझाव दूंगा जो उन वस्तुओं को लौटाता है जो उपभोक्ता कोड को बाद में free()
होना चाहिए।
तो पूछे गए प्रश्न का उत्तर malloc()
और free()
को हटा देना है क्योंकि पुस्तकालय दोनों को संभालता है। हालांकि सावधान रहें यदि आपका प्रोग्राम उस फ़ंक्शन पर कई कॉल करता है और अन्य जो आंतरिक रूप से उस पर भरोसा करते हैं (जैसे get_double()
) तो आप स्मृति से बाहर हो सकते हैं क्योंकि पुस्तकालय मृत स्थान पर बैठा है।