2009-08-08 8 views
8

मैं कुल सी नौसिखिया हूं, मैं सी # से आया हूं। मैं स्मृति प्रबंधन और malloc() फ़ंक्शन के बारे में सीख रहा हूं। मैं भी इस कोड में आए है:आप कैसे जानते हैं कि malloc() के साथ आवंटित करने के लिए कितनी जगह है?

char *a_persons_name = malloc(sizeof(char) + 2); 

मैं क्या समझ में नहीं आता है इस कितनी जगह a_persons_name के लिए आवंटित किया गया है। क्या यह 2 अक्षर आवंटित कर रहा है (उदाहरण के लिए एबी) या कुछ और?

मुझे यह भी पता है कि आप कभी-कभी malloc के साथ "भाग्यशाली" प्राप्त कर सकते हैं और आवंटित स्थान का उपयोग कर सकते हैं (जिसके परिणामस्वरूप डेटा भ्रष्टाचार और सीजी दोष हो सकते हैं)। तो मुझे कैसे पता चलेगा कि मैं कितनी जगह आवंटित कर रहा हूं और मुझे कितना आवश्यकता होगी?

उत्तर

14

वह स्निपेट 2-वर्ण वाले नाम के लिए पर्याप्त स्थान आवंटित कर रहा है।

आम तौर पर स्ट्रिंग बफर कहीं से भरने जा रहा है, यानी I/O। स्ट्रिंग का आकार समय (उदाहरण के लिए फ़ाइल या कीबोर्ड से पढ़ने) से आगे नहीं जाना जाता है, तो तीन तरीकों में से एक आम तौर पर इस्तेमाल कर रहे हैं:

  • किसी भी स्ट्रिंग के लिए अधिकतम आकार को परिभाषित करें, जो आकार का आवंटन + 1 (शून्य टर्मिनेटर के लिए), अधिकांश वर्णों को पढ़ें, और अगर बहुत सारे पात्रों की आपूर्ति की जाती है तो त्रुटि या अंधेरे से छेड़छाड़ की जाती है। बहुत उपयोगकर्ता के अनुकूल नहीं है।

  • चरणों में पुनर्वितरण (अधिमानतः ज्यामितीय श्रृंखला का उपयोग करना, उदाहरण के लिए दोगुनी, वर्गबद्ध व्यवहार से बचने के लिए), और अंत तक पहुंचने तक पढ़ना जारी रखें। कोड के लिए बहुत आसान नहीं है।

  • एक निश्चित आकार आवंटित करें और उम्मीद है कि यह पार नहीं किया जाएगा, और जब यह धारणा विफल हो जाती है तो क्रैश (या स्वामित्व में)। कोड करने में आसान, तोड़ने में आसान। उदाहरण के लिए, मानक सी लाइब्रेरी में gets देखें। (कभी भी इस समारोह का उपयोग करें।)

+2

आवंटित क्यों सभी तरीकों के लिए पर्याप्त स्थान चूसना? कोई आसान तरीका नहीं है! – Kredns

+4

स्ट्रिंग्स सी का सबसे टूटा हिस्सा हैं। मैं एक छद्म-ओओ 'स्ट्रिंगबिल्डर' संरचना या इसी तरह कोडिंग करने की सलाह देता हूं, और उदाहरण बना रहा हूं। StrBufPrintf, StrBufGets, StrBufScanf, आदि इस तरह के संचालन को केंद्रीकृत करने के लिए। मानक सी लाइब्रेरी ज्यादा मदद नहीं करता है। सी ++ थोड़ा बेहतर है, क्योंकि आपके पास आमतौर पर विभिन्न स्ट्रिंग क्लास के 10 से चुनने के लिए चयन किया जाता है, प्रत्येक एक अलग फ्रेमवर्क के लिए इस्तेमाल किया जा रहा है। हाँ, मैं व्यंग्यात्मक हूँ। –

+2

आसान तरीका है (1) ऐसी भाषा का उपयोग करें जहां एक स्ट्रिंग एक मूल प्रकार है; (2) एक पुस्तकालय का उपयोग करें जो स्ट्रिंग व्यवहार प्रदान करता है; या (3) आप जिस भाषा का उपयोग कर रहे हैं उसे सीखें। यदि आप उपकरण का उपयोग कैसे करना सीखना नहीं चाहते हैं, तो आप भी कोशिश क्यों कर रहे हैं। एक और भाषा खोजें जो आपके लिए अधिक अनुकूल है (मैं यहां अपमानजनक होने की कोशिश नहीं कर रहा हूं, केवल व्यावहारिक)। – paxdiablo

1

आपकी कॉल malloc मेमोरी के 3 बाइट आवंटित करेगी। sizeof(char) 1 बाइट और 2 बाइट स्पष्ट रूप से संकेतित हैं। यह आपको आकार 2 की एक स्ट्रिंग के लिए पर्याप्त स्थान देता है (समाप्ति चरित्र के साथ)

5

ठीक है, एक शुरुआत के लिए, sizeof(char) हमेशा होता है 1 है, तो आप सिर्फ malloc(3) सकता है।

जो आप आवंटित कर रहे हैं वह तीन वर्णों के लिए पर्याप्त स्थान है। लेकिन ध्यान रखें कि आपको सी तारों के लिए एक शून्य टर्मिनेटर की आवश्यकता है।

+---+---+---+---+---+----+ 
| x | y | z | z | y | \0 | 
+---+---+---+---+---+----+ 
:

#define NAME_SZ 30 
: : : 
char *name = malloc (NAME_SZ+1); 

(याद रखें कि इस स्ट्रिंग "xyzzy" के रूप में स्मृति में संग्रहीत किया जाता है एक नाम और टर्मिनेटर चरित्र के लिए पर्याप्त संग्रहण प्राप्त करने के लिए:

आप को खोजने के लिए क्या करते हैं जैसी चीजों है गैर चार आधारित सरणियों के साथ कभी कभी

, आप देखेंगे:

int *intArray = malloc (sizeof (int) * 22); 

जो आवंटित करेगा 22 पूर्णांक के लिए पर्याप्त जगह।

+0

(प्रकार और सुविधा) 'int * intArray = malloc (sizeof (* intArray) * 22);' – u0b34a0f6ae

+0

"ठीक है, शुरुआत के लिए, आकार (char) हमेशा 1" गलत है। सी एक चार के आकार के लिए एक कम बाउंड के रूप में 1 बाइट निर्दिष्ट करता है। वास्तविक आकार दोनों आर्किटेक्चर और कंपाइलर निर्भर है। कुछ और अस्पष्ट आर्किटेक्चर पर एक चार 16 बिट्स है। –

+3

नहीं है, वास्तव में, sizeof (चार) * हमेशा * 1. c1x से है, पैरा 3 "sizeof ऑपरेटर 6.5.3.4": एक संकार्य टाइप चार, अहस्ताक्षरित चार, या हस्ताक्षर किए चार, है पर लागू किए जाने (या एक उसके योग्य संस्करण) परिणाम 1. – paxdiablo

1

यह तीन बाइट आवंटित करेगा; आकार के लिए 1 (चार), प्लस दो।बस उस रेखा को संदर्भ से बाहर देखकर, मुझे यह जानने का कोई तरीका नहीं है कि इसे इस तरह आवंटित क्यों किया जाएगा या यदि यह सही है (यह मेरे लिए ख़राब दिखता है)।

आपको जो कुछ भी रखना है उसे पकड़ने के लिए आपको पर्याप्त स्मृति आवंटित करने की आवश्यकता है। उदाहरण के लिए, यदि आप स्ट्रिंग को पकड़ने के लिए मेमोरी आवंटित कर रहे हैं, तो आपको टर्मिनिंग नल के लिए सबसे लंबी स्ट्रिंग अपेक्षित प्लस वन बाइट रखने के लिए पर्याप्त मेमोरी आवंटित करने की आवश्यकता है। यदि आप ASCII तारों से निपट रहे हैं, तो यह आसान है: एक बाइट प्रति चरित्र प्लस वन। यदि आप यूनिकोड तारों का उपयोग कर रहे हैं, तो चीजें अधिक जटिल हो जाती हैं।

3

malloc() स्मृति का एक ब्लॉक आवंटित करेगा और उस स्मृति के लिए सूचक लौट यदि सफल, और यदि असफल शून्य। मेमोरी के ब्लॉक का आकार बाइट्स में malloc के तर्क द्वारा निर्दिष्ट किया गया है।

sizeof ऑपरेटर बाइट्स में इसके तर्क का आकार देता है।

char *someString = malloc(sizeof(char) * 50) 

यह एक 49 चरित्र स्ट्रिंग के लिए पर्याप्त जगह आवंटित करेगा शून्य चरित्र, और कहा कि स्मृति में बिंदु someString सहित नहीं (एक सी शैली स्ट्रिंग एक शून्य ('\0') चरित्र द्वारा समाप्त किया जाना चाहिए)।

ऐसा लगता है कि आपके प्रश्न में यह कोड malloc(sizeof(char) * 2); होना चाहिए, क्योंकि sizeof(char) + 2 समझ में नहीं आता है।

नोट करें कि sizeof(char) हमेशा बराबर 1 (बाइट) की गारंटी है - लेकिन अन्य प्रकारों (जैसे लंबे समय) की स्मृति प्रस्तुति कंपेलरों के बीच भिन्न हो सकती है।

गतिशील रूप से आवंटित स्मृति के साथ आपको भाग्यशाली (अन) भाग्यशाली तरीका है यदि आप आवंटित स्मृति के बाहर पढ़ने/लिखने का प्रयास करते हैं।

उदाहरण के लिए,

char *someString = malloc(10); 
strcpy(someString, "Hello there, world!"); 
printf("%s\n", someString); 

पहली पंक्ति 9 पात्रों के लिए पर्याप्त जगह है, और एक शून्य चरित्र आवंटित करता है।
दूसरी पंक्ति उस स्मृति स्थान में 20 वर्ण (1 9 + एनयूएलएल) की प्रतिलिपि बनाने का प्रयास करती है। यह बफर को ओवररन्स करता है और कुछ अविश्वसनीय रूप से विनोदी हो सकता है, जैसे आसन्न स्मृति को ओवरराइट करना, या सीगफॉल्ट का कारण बनना।

तीसरी पंक्ति काम कर सकती है, उदाहरण के लिए अगर कुछ स्ट्रिंग के बगल में स्मृति आवंटित की गई थी, और "हैलो, दुनिया!" उस मेमोरी स्पेस में भाग गया, यह आपकी स्ट्रिंग प्लस प्रिंट कर सकता है जो अगली मेमोरी स्पेस में था। यदि वह दूसरी जगह पूरी तरह से समाप्त हो गई थी, तो यह तब तक रुक जाएगी - जब तक कि यह नहीं था, इस मामले में यह भटक जाएगा और अंत में segfault।

यह उदाहरण एक बहुत ही सरल ऑपरेशन है, फिर भी गलत जाना बहुत आसान है। सी मुश्किल है - सावधान रहें।

1

पहला बिंदु - यह एक अच्छी आदत है कि कभी भी malloc के तर्क में पूर्ण संख्या न डालें, हमेशा आकार और एकाधिक का उपयोग करें। जैसा ऊपर बताया गया है, कुछ प्रकार के लिए आवंटित स्मृति कंपाइलर और प्लेटफॉर्म के साथ बदलती है। आदेश प्रकार 'ब्लॉब' की एक सरणी के लिए पर्याप्त जगह मिल रही की गारंटी के लिए यह कुछ इस तरह उपयोग करने के लिए सबसे अच्छा है:

blob *p_data = malloc(sizeof(blob) * length_of_array); 

इस तरह, जो कुछ भी प्रकार है, लेकिन ऐसा लगता है कि स्मृति में आप वास्तव में मिल जाएगा सही मात्रा।

दूसरा, segfaults आदि सी, निम्न स्तर की भाषा के रूप में, कोई सीमा जांच नहीं है। इसका मतलब है कि यह जांचने के लिए कुछ भी नहीं है कि आप वास्तव में सरणी में मौजूद इंडेक्स को नहीं देख रहे हैं।असल में यह आपको कहीं भी स्मृति तक पहुंचने से नहीं रोकता है, भले ही यह आपके प्रोग्राम से संबंधित न हो (हालांकि आपका ऑपरेटिंग सिस्टम हो सकता है, यह एक सीजीएफॉल्ट है)। यही कारण है कि, जब भी आप सी में चारों ओर एक सरणी पास करते हैं तो आपको इसकी लंबाई भी पारित करने की आवश्यकता होती है, ताकि सरणी प्राप्त करने वाला फ़ंक्शन जानता है कि यह कितना बड़ा है। यह न भूलें कि 'सरणी' वास्तव में पहले तत्व के लिए सिर्फ एक सूचक है। यह चारों ओर तारों को पार करते समय बहुत ही अनुपयोगी है - प्रत्येक स्ट्रिंग तर्क दो तर्क बन जाएगा, इसलिए एक धोखा का उपयोग किया जाता है। कोई भी मानक सी स्ट्रिंग न्यूल समाप्त हो जाती है। स्ट्रिंग में अंतिम वर्ण ASCII मान 0 होना चाहिए। कोई स्ट्रिंग फ़ंक्शन सरणी के साथ काम करते हैं जब तक वे इसे देखते हैं और फिर रुकें। इस तरह वे सरणी को खत्म नहीं करते हैं, लेकिन यदि यह किसी कारण से नहीं है, तो वे करेंगे। समझा जा रहा है

strlen("Hello") 

5 है, लेकिन यह स्टोर करने के लिए आप एक और चरित्र की जरूरत है। उदा .:

const char str1 = "Hello"; 
char *str2 = malloc(sizeof(char) * (strlen(str1) + 1)); 
strcpy(str2, str1); 

और हाँ, sizeof (चार) है क्योंकि यह 1 होने के लिए परिभाषित किया गया है अनावश्यक है, लेकिन मैं यह स्पष्ट पाते हैं और यह निश्चित रूप से एक अच्छी आदत है।

+0

1) "कुछ इस तरह उपयोग करने के लिए सबसे अच्छा:" के साथ असहमत 'p_data = malloc (sizeof (ब्लॉब) * length_of_array);' 'p_data = malloc (sizeof * p_data * length_of_array);' यह प्रकार कोडिंग पर निर्भर नहीं करता के रूप में सही है और कोड बदलते ही इसे सही रखते हुए। 2) उदाहरण उपयोग: 'str2 = malloc (sizeof * str2 * (strlen (str1) + 1));' – chux

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