मुझे C में मॉलॉक का उपयोग कब करना चाहिए और कब नहीं?


94

मैं समझता हूं कि मॉलोक () कैसे काम करता है। मेरा सवाल है, मैं चीजों को इस तरह से देखूंगा:

#define A_MEGABYTE (1024 * 1024)

char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
some_memory = (char *)malloc(size_to_allocate);
sprintf(some_memory, "Hello World");
printf("%s\n", some_memory);
free(some_memory);

मैंने संक्षिप्तता के लिए त्रुटि जाँच को छोड़ दिया। मेरा सवाल यह है कि क्या आप केवल मेमोरी में कुछ स्थिर भंडारण के लिए सूचक को प्रारंभ करके ऊपर नहीं कर सकते हैं? शायद:

char *some_memory = "Hello World";

वास्तव में आपको उन मूल्यों को घोषित करने / शुरू करने के बजाय स्मृति को आवंटित करने की आवश्यकता है जो आपको बनाए रखने की आवश्यकता है?


5
पुन :: मैं संक्षिप्तता की जाँच के लिए त्रुटि जाँच छोड़ दिया - दुर्भाग्य से कई प्रोग्रामर त्रुटि जाँच छोड़ देते हैं क्योंकि उन्हें एहसास नहीं होता कि वे malloc()विफल हो सकते हैं!
एंड्रयू

जवाबों:


132
char *some_memory = "Hello World";

एक स्ट्रिंग स्थिरांक के लिए एक पॉइंटर बना रहा है। इसका मतलब है कि स्ट्रिंग "हैलो वर्ल्ड" मेमोरी के रीड-ओनली हिस्से में कहीं और होगा और आपके पास इसके लिए केवल एक पॉइंटर होगा। आप स्ट्रिंग को केवल-पढ़ने के लिए उपयोग कर सकते हैं। आप इसमें परिवर्तन नहीं कर सकते । उदाहरण:

some_memory[0] = 'h';

परेशानी पूछ रहा है।

दूसरी ओर

some_memory = (char *)malloc(size_to_allocate);

एक चार सरणी (एक चर) और उस आवंटित मेमोरी में some_memory अंक आवंटित कर रहा है। अब यह एरे पढ़ने और लिखने दोनों है। अब आप कर सकते हैं:

some_memory[0] = 'h';

और सरणी सामग्री "हैलो वर्ल्ड" में बदल जाती है


19
बस स्पष्ट करने के लिए, जितना मुझे यह उत्तर पसंद है (मैंने आपको +1 दिया था), आप केवल एक चरित्र सरणी का उपयोग करके बिना मॉलोक () के बिना भी ऐसा कर सकते हैं। कुछ इस तरह: char some_memory [] = "हैलो"; some_memory [0] = 'W'; काम भी करेगा।
रैंडमोबिट्स

19
तुम सही हो। तुम यह कर सकते हो। जब आप Malloc () का उपयोग करते हैं, तो मेमोरी को गतिशील रूप से रन समय पर आवंटित किया जाता है, इसलिए आपको संकलन समय पर सरणी आकार को ठीक करने की आवश्यकता नहीं होती है, आप इसे realloc का उपयोग करके इसे बड़ा या छोटा कर सकते हैं (जब आप करते हैं तो इनमें से कुछ भी नहीं किया जा सकता है: char some_emory [] = "हैलो"; यहां भले ही आप ऐरे की सामग्री को बदल सकते हैं, लेकिन इसका आकार निश्चित है। इसलिए अपनी आवश्यकताओं के आधार पर आप तीन विकल्पों में से किसी एक का उपयोग करते हैं: 1) पॉइंटर कांस्टेबल को संकेत 2) गतिशील रूप से आवंटित सरणी 3) निश्चित आकार, संकलन समय आवंटित सरणी।
18

यह पढ़ने के लिए जोर देने के लिए केवल आपको लिखना चाहिए const char *s = "hi";क्या यह वास्तव में मानक द्वारा आवश्यक नहीं है?
थिस जु

@ नहीं, नहीं क्योंकि आपने स्ट्रिंग शाब्दिक "हाय" के आधार पते के लिए प्रारंभिक सूचक घोषित किया था। s को नॉन-कॉस्ट चार की ओर इंगित करने के लिए पूरी तरह से कानूनी रूप से पुन: सौंपा जा सकता है। यदि आप एक निरंतर सूचक को केवल स्ट्रिंग को पढ़ना चाहते हैं, तो आपको जरूरत हैconst char const* s;
Rob11311

38

उस सटीक उदाहरण के लिए, मॉलोक बहुत कम उपयोग का है।

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

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


4
मेमोरी जीवन चक्र और कब और कैसे इसे डील करना है, इससे संबंधित प्रश्न कई सामान्य पुस्तकालयों और सॉफ्टवेयर घटकों के साथ एक महत्वपूर्ण मुद्दा है। वे आम तौर पर एक अच्छी तरह से प्रलेखित नियम है: आप के लिए एक सूचक पार कर लेते हैं " यह मेरी दिनचर्या में से एक है, आप इसे malloc'd है की जरूरत है मैं इसे का ट्रैक रखने देंगे, और यह मुक्त जब मैं इसके साथ किया हूँ।। " गंदा कीड़े का एक सामान्य स्रोत इस तरह के पुस्तकालय को सांख्यिकीय रूप से आवंटित स्मृति के लिए एक सूचक पारित करना है। जब पुस्तकालय इसे मुक्त () करने की कोशिश करता है, तो प्रोग्राम क्रैश हो जाता है। मैंने हाल ही में एक बग को ठीक करने में बहुत समय बिताया, जो किसी और ने लिखा था।
बॉब मर्फी

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

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

@ थोबा: उन गंदे कीड़े, सम्मेलन बनाते हैं कि आवंटनकर्ता स्मृति को बहुत बेहतर बनाता है, आखिरकार आप इसे रीसाइक्लिंग कर सकते हैं। मान लीजिए कि आपने संदर्भों की स्थानीयता सुधारने के लिए कॉलोक के साथ मेमोरी आवंटित की है, जो उन पुस्तकालयों की टूटी हुई प्रकृति को उजागर करता है, क्योंकि आपको पूरे ब्लॉक के लिए बस एक बार मुफ्त कॉल करने की आवश्यकता है। सौभाग्य से मुझे उन पुस्तकालयों का उपयोग नहीं करना पड़ा है जो स्मृति को 'मॉलोक-एड' के रूप में निर्दिष्ट करते हैं, यह एक पॉसिक्स परंपरा नहीं है और बहुत संभावना है कि इसे बग माना जाएगा। यदि उन्हें "पता" है कि आपको मॉलॉक का उपयोग करना है, तो पुस्तकालय की दिनचर्या आपके लिए क्यों नहीं है?
Rob11311

17

मॉलोक आपके हैलो वर्ल्ड उदाहरण जैसी स्थैतिक घोषणाओं की तुलना में रनटाइम के दौरान मेमोरी को आबंटित, वास्तविक और मुक्त करने के लिए एक अद्भुत उपकरण है, जिसे संकलन-समय पर संसाधित किया जाता है और इस प्रकार इसका आकार नहीं बदला जा सकता है।

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

बेशक, आपके द्वारा दिए गए एक तुच्छ उदाहरण में, मॉलॉक जादुई "सही काम के लिए सही उपकरण" नहीं है, लेकिन अधिक जटिल मामलों के लिए (उदाहरण के लिए रनटाइम पर एक मनमाना आकार का सरणी बनाना), यह एकमात्र तरीका है जाओ।


7

यदि आपको स्मृति का सही आकार नहीं पता है जिसका आपको उपयोग करने की आवश्यकता है, तो आपको गतिशील आवंटन ( malloc) की आवश्यकता है। एक उदाहरण तब हो सकता है जब कोई उपयोगकर्ता आपके एप्लिकेशन में कोई फ़ाइल खोलता है। आपको फ़ाइल की सामग्री को मेमोरी में पढ़ने की आवश्यकता होगी, लेकिन निश्चित रूप से आप फ़ाइल के आकार को पहले से नहीं जानते हैं, क्योंकि उपयोगकर्ता रनटाइम पर फ़ाइल का चयन करता है। इसलिए मूल रूप से आपको उस mallocसमय की आवश्यकता होती है जब आप उस डेटा का आकार नहीं जानते हैं जो आप पहले से काम कर रहे हैं। कम से कम इसका उपयोग करने के मुख्य कारणों में से एक है malloc। आपके उदाहरण में एक साधारण स्ट्रिंग के साथ, जिसे आप पहले से ही संकलन समय के आकार के साथ जानते हैं (साथ ही आप इसे संशोधित नहीं करना चाहते हैं), यह गतिशील रूप से आवंटित करने के लिए बहुत मायने नहीं रखता है।


थोड़ा ऑफ-टॉपिक, लेकिन ... आपको बहुत सावधानी बरतनी होगी कि उपयोग करते समय मेमोरी लीक न हो malloc। इस कोड पर विचार करें:

int do_something() {
    uint8_t* someMemory = (uint8_t*)malloc(1024);

    // Do some stuff

    if ( /* some error occured */ ) return -1;

    // Do some other stuff

    free(someMemory);
    return result;
}

क्या आप देखते हैं कि इस कोड में क्या गलत है? वहाँ के बीच एक सशर्त वापसी कथन है mallocऔर free। यह पहली बार में ठीक लग सकता है, लेकिन इसके बारे में सोचें। यदि कोई त्रुटि है, तो आप आवंटित की गई मेमोरी को मुक्त किए बिना वापस लौटने वाले हैं। यह मेमोरी लीक का एक सामान्य स्रोत है।

बेशक यह एक बहुत ही सरल उदाहरण है, और यहां गलती को देखना बहुत आसान है, लेकिन पॉइंटर्स, mallocएस, freeएस और सभी प्रकार की त्रुटि से निपटने के साथ कोड की सैकड़ों लाइनों की कल्पना करें । चीजें वास्तव में बहुत तेजी से गड़बड़ हो सकती हैं। यह उन कारणों में से एक है जो मैं लागू मामलों में C पर आधुनिक C ++ को पसंद करता हूं, लेकिन यह एक संपूर्ण नोटेर विषय है।

इसलिए जब भी आप उपयोग करते हैं malloc, तो हमेशा सुनिश्चित करें कि आपकी मेमोरी freeयथासंभव घनी हो।


बहुत बढ़िया उदाहरण! जाने का रास्ता ^ _ ^
मूसा अल-परेशानी

6
char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");

गैरकानूनी है, स्ट्रिंग शाब्दिक हैं const

यह स्टैक पर या विश्व स्तर पर (जहां यह घोषित किया गया है) के आधार पर 12-बाइट चार सरणी आवंटित करेगा।

char some_memory[] = "Hello World";

यदि आप और अधिक हेरफेर के लिए कमरा छोड़ना चाहते हैं, तो आप यह निर्दिष्ट कर सकते हैं कि सरणी को बड़ा आकार देना चाहिए। (कृपया स्टैक पर 1MB न डालें, हालाँकि)

#define LINE_LEN 80

char some_memory[LINE_LEN] = "Hello World";
strcpy(some_memory, "Goodbye, sad world...");
printf("%s\n", some_memory);

5

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.