2010-04-19 13 views
11

मैं सी/सी ++ में जा रहा हूं और बहुत सी शर्तें मेरे लिए अपरिचित हो रही हैं। उनमें से एक एक चर या सूचक है जो शून्य से समाप्त होता है। शून्य में समाप्त होने वाली स्मृति में किसी स्थान के लिए इसका क्या अर्थ है?"शून्य से समाप्त" होने का क्या अर्थ है?

+6

यह वाक्य एक अवधि के द्वारा समाप्त हो जाता है। तो यह एक है। लेकिन यह एक नहीं! – polygenelubricants

+2

जोएल के पास इस (और संबंधित चीजों) के बारे में एक अच्छा लेख है: http://www.joelonsoftware.com/articles/fog0000000319.html – NomeN

उत्तर

16

ASCII में स्ट्रिंग Hi लें। स्मृति में इसका सबसे सरल प्रतिनिधित्व दो बाइट्स है:

0x48 
0x69 

लेकिन स्मृति का वह टुकड़ा कहां समाप्त होता है? जब तक आप स्ट्रिंग में बाइट्स की संख्या को पार करने के लिए तैयार नहीं होते हैं, तो आप नहीं जानते - स्मृति के टुकड़े आंतरिक रूप से लंबाई नहीं रखते हैं।क्योंकि वहाँ NUL से पहले दो अक्षर हैं,

0x48 
0x69 
0x00 

स्ट्रिंग अब स्पष्ट रूप से दो वर्ण लंबा है:

तो सी एक मानक है कि तार एक शून्य बाइट, यह भी एक NUL चरित्र के रूप में जाना के साथ समाप्त होता है।

+1

और बफर ओवरफ़्लो तब होता है जब आप यह महसूस करने में विफल रहते हैं कि आपको दो वर्णों को स्टोर करने के लिए तीन बाइट्स की आवश्यकता है। – MSalters

+1

@MSalters: नहीं, वे तब होते हैं जब आप महसूस करते हैं कि लंबाई-दो स्ट्रिंग में तीन वर्ण होते हैं। :-) –

14

यह स्ट्रिंग में वर्णों (उदाहरण के लिए) के अनुक्रम के अंत को इंगित करने के लिए एक आरक्षित मान है।

null (or NUL) terminated के रूप में अधिक सही ढंग से जाना जाता है। ऐसा इसलिए है क्योंकि '0' के लिए वर्ण कोड होने के बजाय उपयोग किया जाने वाला मान शून्य है। भेद को स्पष्ट करने के लिए ASCII character set की एक तालिका देखें।

यह आवश्यक है क्योंकि सी जैसे भाषाओं में char डेटा प्रकार है, लेकिन string डेटा प्रकार नहीं है। इसलिए यह तय करने के लिए devleoper के लिए छोड़ दिया जाता है कि उनके आवेदन में तारों का प्रबंधन कैसे करें। ऐसा करने का सामान्य तरीका है char एस की सरणी को समाप्त करने के लिए उपयोग किए जाने वाले शून्य मान के साथ (यानी स्ट्रिंग का अंत इंगित करें) है।

ध्यान दें कि स्ट्रिंग की लंबाई और मूल सरणी की मूल सरणी के बीच एक अंतर है।

char name[50]; 

यह 50 अक्षरों की एक सरणी की घोषणा की। हालांकि, इन मानों को अनियंत्रित किया जाएगा। इसलिए यदि मैं स्ट्रिंग "Hello" (5 वर्ण लंबा) स्टोर करना चाहता हूं तो मैं वास्तव में शेष 45 वर्णों को रिक्त स्थान (या कुछ अन्य मान) पर सेट करना नहीं चाहता हूं। इसके बजाय मैं अपनी स्ट्रिंग में अंतिम चरित्र के बाद एक एनयूएल मान स्टोर करता हूं।

पास्कल, जावा और सी # जैसी हालिया भाषाओं में एक विशिष्ट string प्रकार परिभाषित किया गया है। स्ट्रिंग में वर्णों की संख्या इंगित करने के लिए उनके पास हेडर वैल्यू है। इसमें कुछ लाभ हैं; सबसे पहले आपको इसकी लंबाई जानने के लिए स्ट्रिंग के अंत तक चलने की आवश्यकता नहीं है, दूसरी बात यह है कि आपकी स्ट्रिंग contain null characters हो सकती है।

विकिपीडिया में String (computer science) प्रविष्टि में और जानकारी है।

+0

पुन: अधिक हालिया भाषाएं: आईआईआरसी, जिसे पास्कल स्ट्रिंग कहा जाता है – Hasturkun

+0

पास्कल तार विशेष रूप से एकल का उपयोग करते हैं स्ट्रिंग लंबाई पकड़ने के लिए बाइट। जैसा कि आप जल्दी से अनुमान लगा सकते हैं, यह वास्तव में पर्याप्त नहीं है! आधुनिक 'स्ट्रिंग' प्रकार शायद इसके बजाय 'size_t' का उपयोग कर रहे हैं; यदि आपकी स्ट्रिंग उसमें फिट नहीं होगी, तो स्ट्रिंग पूरी तरह स्मृति में नहीं होने वाली है। –

0

सी में Arrays और स्ट्रिंग केवल स्मृति स्थान के लिए एक पॉइंटर्स है। सूचक द्वारा आप सरणी की शुरुआत पा सकते हैं। सरणी का अंत अनिर्धारित है। चरित्र सरणी (जो स्ट्रिंग है) का अंत शून्य-बाइट है।

तो, स्मृति में स्ट्रिंग हैलो लिखा है के रूप में:

68 65 6c 6c 6f 00         |hello| 
0

यह कैसे सी तार स्मृति में जमा हो जाती है को दर्शाता है। स्ट्रिंग इट्रल्स में \ 0 द्वारा प्रतिनिधित्व किया गया एनयूएल चरित्र स्मृति में सी स्ट्रिंग के अंत में मौजूद होता है। उदाहरण के लिए लंबाई जैसे सी स्ट्रिंग से जुड़े कोई अन्य मेटा डेटा नहीं है। एनयूएल चरित्र और नल सूचक के बीच विभिन्न वर्तनी नोट करें।

0

सी-शैली तारों को एक एनयूएल चरित्र ('\ 0') द्वारा समाप्त कर दिया जाता है। यह स्ट्रिंग के अंत की पहचान करने के लिए स्ट्रिंग्स (जैसे स्ट्रेलन, स्ट्रैपी) पर काम करने वाले कार्यों के लिए मार्कर प्रदान करता है।

4

एक शून्य

जब अपने नुकीले बालों वाली मालिक आप आग यह द्वारा समाप्त।

0

वहाँ दो सामान्य तरीके सरणियों अलग-लंबाई सामग्री (स्ट्रिंग्स) की तरह हो सकता है संभाल करने के लिए कर रहे हैं। सबसे पहले सरणी में संग्रहीत डेटा की लंबाई को अलग रखना है। फोरट्रान और एडा और सी ++ की एसडीडी :: स्ट्रिंग जैसी भाषाएं ऐसा करती हैं। ऐसा करने का नुकसान यह है कि आपको किसी भी तरह से उस अतिरिक्त जानकारी को अपने सरणी से निपटने वाली सभी चीज़ों को पास करना होगा।

अन्य तरीके से, सरणी के अंत में एक अतिरिक्त गैर डेटा तत्व आरक्षण एक प्रहरी के रूप में काम करने के लिए है। सेंटीनेल के लिए आप एक ऐसे मान का उपयोग करते हैं जो वास्तविक डेटा में कभी प्रकट नहीं होना चाहिए। तारों के लिए, 0 (या "एनयूएल") एक अच्छी पसंद है, क्योंकि यह अप्रत्याशित है और ASCII में कोई अन्य उद्देश्य नहीं देता है। तो क्या सी (और कई भाषाओं सी से नकल) करते हैं (या "द्वारा समाप्त कर रहे हैं") एक 0.

यह करने के लिए कई कमियां हैं ग्रहण करने के लिए कि सभी स्ट्रिंग्स में पहुंचते हैं। एक बात के लिए, यह धीमा है। किसी भी समय नियमित रूप से स्ट्रिंग की लंबाई जानने की आवश्यकता होती है, यह एक ओ (एन) ऑपरेशन (0 की तलाश में पूरी स्ट्रिंग के माध्यम से खोज रहा है)। एक और समस्या यह है कि आप एक दिन किसी कारण से अपनी स्ट्रिंग में 0 डालना चाहते हैं, इसलिए अब आपको स्ट्रिंग रूटीन के पूरे दूसरे सेट की आवश्यकता है जो शून्य को अनदेखा करता है और वैसे भी एक अलग लंबाई का उपयोग करता है (उदाहरण: strnlen())। तीसरी बड़ी समस्या यह है कि अगर कोई अंत में उस 0 को रखना भूल जाता है (या यह किसी भी तरह से मिटा दिया जाता है), तो दसवीं चेक करने के लिए अगला स्ट्रिंग ऑपरेशन मेमोरी के माध्यम से मार्चिंग तक चलेगा जब तक कि यह यादृच्छिक रूप से किसी अन्य 0 को नहीं ढूंढता, दुर्घटनाओं, या उपयोगकर्ता धैर्य खो देता है और इसे मारता है। ट्रैक करने के लिए ऐसी बग एक गंभीर पिटा हो सकती है।

इन सभी कारणों से, सी दृष्टिकोण आमतौर पर अन्याय के साथ देखा जाता है।

0

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

यह चाल सरणी के अंत तक एक सेंटीनेल मान जोड़कर सरणी आकार के चारों ओर गुजरने से बचने के लिए है। आमतौर पर, शून्य का कुछ रूप उपयोग किया जाता है, लेकिन यह कुछ और हो सकता है (जैसे NAN यदि सरणी में फ़्लोटिंग पॉइंट मान होते हैं)।

  1. सी तार, निश्चित रूप से:

    यहाँ इस अवधारणा के तीन उदाहरण हैं। स्ट्रिंग में एक शून्य वर्ण जोड़ा गया है: "Hello"48 65 6c 6c 6f 00 के रूप में एन्कोड किया गया है।

  2. पॉइंटर्स के सरणी स्वाभाविक रूप से शून्य समाप्ति की अनुमति देते हैं, क्योंकि शून्य सूचक (जो शून्य को संबोधित करने वाला इंगित करता है) को किसी वैध ऑब्जेक्ट को इंगित करने के लिए परिभाषित नहीं किया जाता है।जैसे, अगर आप इस तरह कोड खोज सकते हैं:

    Foo list[] = { somePointer, anotherPointer, NULL }; 
    bar(list); 
    

    बजाय

    Foo list[] = { somePointer, anotherPointer }; 
    bar(sizeof(list)/sizeof(*list), list); 
    

    यही कारण है कि execvpe() केवल तीन तर्कों, जिनमें से दो उपयोगकर्ता परिभाषित लंबाई के एरे पारित की जरूरत है। चूंकि execvpe() तक पहुंचने वाले सभी (संभवतः बहुत सारे) तार हैं, यह छोटा फ़ंक्शन वास्तव में शून्य समाप्ति के दो स्तरों को खेलता है: स्ट्रिंग सूचियों को समाप्त करने वाले शून्य पॉइंटर्स, और नल वर्ण स्वयं स्ट्रिंग को समाप्त करते हैं।

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

    Foo list[] = { 
        { someValue, somePointer }, 
        { anotherValue, anotherPointer }, 
        { 0, NULL } 
    }; 
    bar(list); 
    

    या यहाँ तक कि

    Foo list[] = { 
        { someValue, somePointer }, 
        { anotherValue, anotherPointer }, 
        {} //C zeros out an object initialized with an empty initializer list. 
    }; 
    bar(list); 
    
संबंधित मुद्दे