अशक्त तार के लिए तर्क क्या है?


281

जितना मैं सी और सी ++ से प्यार करता हूं, मैं मदद नहीं कर सकता, लेकिन अशक्त समाप्ति के विकल्प पर अपना सिर खरोंच कर सकता हूं:

  • लंबाई पहले (यानी पास्कल) तार सी के पहले मौजूद थी
  • लंबाई के पहले से लगे हुए तार कई एल्गोरिदम को निरंतर समय लंबाई देखने की अनुमति देकर तेजी से बनाते हैं।
  • लंबाई उपसर्गों की स्ट्रिंग बफर त्रुटि उत्पन्न करने के लिए इसे और अधिक कठिन बनाती है।
  • यहां तक ​​कि एक 32 बिट मशीन पर, यदि आप स्ट्रिंग को उपलब्ध स्मृति के आकार की अनुमति देते हैं, तो एक लंबाई उपसर्ग स्ट्रिंग केवल तीन बाइट्स है जो एक शून्य समाप्त स्ट्रिंग से अधिक व्यापक है। 16 बिट मशीनों पर यह एक सिंगल बाइट है। 64 बिट मशीनों पर, 4GB एक उचित स्ट्रिंग लंबाई की सीमा है, लेकिन भले ही आप इसे मशीन शब्द के आकार में विस्तारित करना चाहते हैं, 64 बिट मशीनों में आमतौर पर अतिरिक्त सात बाइट्स एक अशक्त तर्क की तरह पर्याप्त स्मृति होती है। मुझे पता है कि मूल सी मानक पागलपन वाली मशीनों (स्मृति के संदर्भ में) के लिए लिखा गया था, लेकिन दक्षता तर्क मुझे यहां नहीं बेचता है।
  • बहुत अधिक हर दूसरी भाषा (यानी पर्ल, पास्कल, पायथन, जावा, सी #, आदि) लंबाई उपसर्गों का उपयोग करती है। ये भाषाएं आमतौर पर स्ट्रिंग हेरफेर बेंचमार्क में सी को हरा देती हैं क्योंकि वे स्ट्रिंग के साथ अधिक कुशल हैं।
  • C ++ ने इसे std::basic_stringटेम्प्लेट के साथ थोड़ा ठीक किया , लेकिन अशक्त समाप्त होने वाले तार की अपेक्षा करने वाले सादे वर्ण सरणियाँ अभी भी व्याप्त हैं। यह भी अपूर्ण है क्योंकि इसमें ढेर आवंटन की आवश्यकता होती है।
  • अशक्त समाप्त तारों को एक वर्ण (अर्थात्, अशक्त) को आरक्षित करना पड़ता है, जो स्ट्रिंग में मौजूद नहीं हो सकता है, जबकि लंबाई के उपसर्गों में अंतर्निहित नल हो सकते हैं।

इनमें से कई चीजें हाल ही में सी की तुलना में अधिक प्रकाश में आई हैं, इसलिए यह सी के लिए समझ में नहीं आएगा उनके बारे में पता नहीं है। हालांकि, सी होने से पहले कई सादे थे। क्यों स्पष्ट रूप से बेहतर लंबाई उपसर्ग के बजाय अशक्त तार को चुना जाएगा?

संपादित करें : चूंकि कुछ लोगों ने मेरे दक्षता बिंदु पर उपरोक्त तथ्यों (और पहले से उपलब्ध कराए गए लोगों को पसंद नहीं किया), वे कुछ चीजों से उपजी हैं:

  • शून्य समाप्त स्ट्रिंग्स का उपयोग करने वाले कॉनैट को ओ (एन + एम) समय की जटिलता की आवश्यकता होती है। लंबाई उपसर्ग अक्सर केवल ओ (एम) की आवश्यकता होती है।
  • शून्य समाप्त स्ट्रिंग्स का उपयोग करने वाली लंबाई के लिए O (n) समय की जटिलता की आवश्यकता होती है। लंबाई उपसर्ग हे (1) है।
  • लंबाई और समतल अब तक के सबसे आम स्ट्रिंग ऑपरेशन हैं। ऐसे कई मामले हैं जहां अशक्त तार अधिक कुशल हो सकते हैं, लेकिन ये अक्सर कम होते हैं।

नीचे दिए गए जवाबों से, ये कुछ ऐसे मामले हैं जहाँ अशक्त तार अधिक कुशल हैं:

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

उपरोक्त में से कोई भी लंबाई और कंकट के रूप में लगभग आम नहीं है।

नीचे दिए गए उत्तरों में एक और जोर दिया गया है:

  • आपको स्ट्रिंग के अंत में कटौती करने की आवश्यकता है

लेकिन यह एक गलत है - यह शून्य समाप्त और लंबाई उपसर्गों के लिए एक ही समय है। (शून्य समाप्त किए गए तार सिर्फ एक नल को चिपकाते हैं जहां आप नया अंत चाहते हैं, लंबाई उपसर्ग केवल उपसर्ग से घटाते हैं।)


110
मैंने हमेशा सोचा कि यह सभी C ++ प्रोग्रामर्स के लिए अपनी खुद की स्ट्रिंग लाइब्रेरी लिखने का एक संस्कार है।
जूलियट

31
अब तर्कसंगत स्पष्टीकरण की उम्मीद के बारे में यह क्या है। मुझे लगता है कि आप x86 या डॉस के लिए एक तर्क सुनना चाहते हैं? जहां तक ​​मेरा सवाल है, सबसे खराब तकनीक जीतती है। हर बार। और सबसे खराब स्ट्रिंग प्रतिनिधित्व।
११:१०

4
आप यह दावा क्यों करते हैं कि लम्बाई उपसर्ग के तार श्रेष्ठ हैं? आखिरकार, सी लोकप्रिय हो गया क्योंकि इसमें अशक्त-शब्द का उपयोग किया गया, जिसने इसे अन्य भाषाओं से अलग कर दिया।
डैनियल सी। सोबरल

44
@ डैनियल: सी लोकप्रिय हो गया क्योंकि यह वॉन न्यूमैन मशीनों पर निष्पादन योग्य कार्यक्रमों का एक सरल, कुशल और पोर्टेबल प्रतिनिधित्व है, और क्योंकि इसका उपयोग यूनिक्स के लिए किया गया था। यह निश्चित रूप से नहीं है क्योंकि यह अशक्त समाप्त तार का उपयोग करने का फैसला किया। यदि यह एक अच्छा डिजाइन निर्णय था, तो लोगों ने इसे कॉपी किया होगा, और उन्होंने ऐसा नहीं किया। उन्होंने निश्चित रूप से सी। से अन्य सभी चीजों की नकल की है
बिली ओनेल

4
यदि आप स्ट्रिंग्स में से किसी एक को नष्ट करते हैं तो कॉनैट केवल ओ (एम) है। नहीं तो वही गति। सी स्ट्रिंग्स (ऐतिहासिक रूप से) का सबसे आम उपयोग मुद्रण और स्कैनिंग कर रहे थे। इन दोनों में, शून्य-समाप्ति तेज है क्योंकि यह एक रजिस्टर को बचाता है।
डैनियल सी। सोबरल

जवाबों:


195

से घोड़े के मुंह

BCPL, B, या C में से कोई भी भाषा में दृढ़ता से वर्ण डेटा का समर्थन नहीं करता है; प्रत्येक उपचार पूर्णांक के वैक्टर की तरह तार करता है और कुछ सम्मेलनों द्वारा सामान्य नियमों को पूरक करता है। बीसीपीएल और बी दोनों में एक स्ट्रिंग शाब्दिक, स्ट्रिंग के पात्रों के साथ आरंभिक स्थैतिक क्षेत्र के पते को दर्शाता है, जो कोशिकाओं में पैक किया जाता है। बीसीपीएल में, पहले पैक किए गए बाइट में स्ट्रिंग में वर्णों की संख्या होती है; बी में, कोई गिनती नहीं है और तारों को एक विशेष चरित्र द्वारा समाप्त किया जाता है, जिसे बी ने वर्तनी दी थी *e। यह परिवर्तन आंशिक रूप से 8-10 या 9-बिट स्लॉट में गिनती को रखने के कारण होने वाली एक स्ट्रिंग की लंबाई पर सीमा से बचने के लिए किया गया था, और आंशिक रूप से क्योंकि हमारे अनुभव में, एक टर्मिनेटर का उपयोग करने की तुलना में कम सुविधाजनक, गिनती बनाए रखना प्रतीत होता है।

डेनिस एम रिची, सी भाषा का विकास


12
एक अन्य प्रासंगिक उद्धरण: "... स्ट्रिंग्स के शब्दार्थ पूरी तरह से अधिक सामान्य नियमों द्वारा सभी सरणियों को नियंत्रित कर रहे हैं, और परिणामस्वरूप भाषा का वर्णन करना आसान है ..."
AShelly

151

C के पास भाषा के भाग के रूप में एक स्ट्रिंग नहीं है। C में एक 'string' केवल char to char का संकेत है। तो शायद आप गलत सवाल पूछ रहे हैं।

"एक स्ट्रिंग प्रकार छोड़ने के लिए तर्क क्या है" अधिक प्रासंगिक हो सकता है। इसके लिए मैं यह बताना चाहूंगा कि C कोई ऑब्जेक्ट ओरिएंटेड भाषा नहीं है और इसमें केवल मूल मूल्य प्रकार हैं। एक स्ट्रिंग एक उच्च स्तर की अवधारणा है जिसे किसी प्रकार से अन्य प्रकार के मूल्यों को मिलाकर लागू किया जाना है। C, अमूर्तता के निचले स्तर पर है।

नीचे उग्र दस्ते की रोशनी में:

मैं केवल यह बताना चाहता हूं कि मैं यह कहने की कोशिश नहीं कर रहा हूं कि यह एक मूर्खतापूर्ण या बुरा सवाल है, या यह कि स्ट्रिंग्स का प्रतिनिधित्व करने का सी तरीका सबसे अच्छा विकल्प है। मैं स्पष्ट करने की कोशिश कर रहा हूं कि यदि आप इस तथ्य को ध्यान में रखते हैं कि सी एक बाइट सरणी से डेटाटाइप के रूप में एक स्ट्रिंग को विभेदित करने के लिए कोई तंत्र नहीं है, तो यह प्रश्न स्पष्ट रूप से रखा जाएगा। क्या यह आज के कंप्यूटर के प्रसंस्करण और मेमोरी पावर के प्रकाश में सबसे अच्छा विकल्प है? शायद ऩही। लेकिन हमेशा दृष्टि 20/20 है और वह सब :)


29
char *temp = "foo bar";सी में एक वैध बयान है ... हे! क्या वह तार नहीं है? क्या यह शून्य नहीं है?
यानिक रोचोन

56
@ यानिक: संकलक को अंत में एक अशक्त के साथ चार की एक सरणी बनाने के लिए बताने का एक सुविधाजनक तरीका है। यह एक 'स्ट्रिंग' नहीं है
रॉबर्ट एस सियाकियो

28
@ कलेवर: लेकिन इसका मतलब सिर्फ इतना हो सकता है कि "इस स्ट्रिंग सामग्री के साथ एक मेमोरी बफर बनाएं और एक दो बाइट की लंबाई उपसर्ग है",
बिली ओनेल

14
@ बिली: चूंकि एक 'स्ट्रिंग' वास्तव में चार्ट के लिए केवल एक पॉइंटर है, जो बाइट के लिए एक पॉइंटर के बराबर है, तो आपको कैसे पता चलेगा कि आप जिस बफर के साथ काम कर रहे हैं वह वास्तव में 'स्ट्रिंग' होने का इरादा है? आपको इसे निरूपित करने के लिए चार / बाइट * के अलावा एक नए प्रकार की आवश्यकता होगी। शायद एक संरचना?
रॉबर्ट एस सियाकियो

27
मुझे लगता है कि @calavera सही है, सी में स्ट्रिंग्स के लिए डेटा प्रकार नहीं है। ठीक है, आप एक स्ट्रिंग की तरह एक सरणी पर विचार कर सकते हैं, लेकिन इसका मतलब यह नहीं है कि यह हमेशा एक स्ट्रिंग है (स्ट्रिंग के लिए मेरा मतलब एक निश्चित अर्थ के साथ वर्णों का एक क्रम है)। एक बाइनरी फ़ाइल वर्णों की एक सरणी है, लेकिन उन वर्णों का मानव के लिए कोई मतलब नहीं है।
ब्लैकबियर

106

प्रश्न को एक Length Prefixed Strings (LPS)बनाम zero terminated strings (SZ)बात के रूप में पूछा जाता है, लेकिन ज्यादातर लंबाई उपसर्गों के लाभ को उजागर करता है। यह भारी लग सकता है, लेकिन ईमानदार होने के लिए हमें एलपीएस की कमियां और एसजेड के फायदे पर भी विचार करना चाहिए।

जैसा कि मैंने इसे समझा है, इस सवाल को एक पक्षपातपूर्ण तरीके से भी पूछा जा सकता है कि "शून्य समाप्त स्ट्रिंग्स के फायदे क्या हैं?"।

ज़ीरो टर्मिनेटेड स्ट्रिंग्स के फायदे (मैं देख रहा हूँ):

  • बहुत सरल, भाषा में नई अवधारणाओं को पेश करने की कोई आवश्यकता नहीं है, char arrays / char संकेत कर सकते हैं।
  • मुख्य भाषा में दोहरे उद्धरण चिह्नों के बीच कुछ को बदलने के लिए न्यूनतम वाक्यविन्यास चीनी शामिल है (वास्तव में बाइट्स का एक गुच्छा)। कुछ मामलों में इसका उपयोग पाठ के साथ पूरी तरह से असंबंधित चीजों को शुरू करने के लिए किया जा सकता है। उदाहरण के लिए xpm छवि फ़ाइल स्वरूप एक मान्य C स्रोत है जिसमें एक स्ट्रिंग के रूप में एन्कोडेड छवि डेटा होता है।
  • वैसे, आप कर सकते हैं एक स्ट्रिंग शाब्दिक में एक शून्य डाल दिया, संकलक बस भी शाब्दिक के अंत में एक दूसरे से जोड़ देगा: "this\0is\0valid\0C"। क्या यह एक तार है? या चार तार? या बाइट्स का एक गुच्छा ...
  • फ्लैट कार्यान्वयन, कोई छिपा हुआ अप्रत्यक्ष, कोई छिपा हुआ पूर्णांक नहीं।
  • कोई छिपी हुई स्मृति आवंटन शामिल नहीं है (अच्छी तरह से, कुछ बदनाम गैर-मानक कार्य जैसे स्ट्रैपअप आवंटन का प्रदर्शन करते हैं, लेकिन यह ज्यादातर समस्या का एक स्रोत है)।
  • छोटे या बड़े हार्डवेयर के लिए कोई विशेष समस्या नहीं है (8 बिट्स माइक्रोकंट्रोलर पर 32 बिट्स प्रीफिक्स लंबाई का प्रबंधन करने के लिए बोझ की कल्पना करें, या कम से कम 256 बाइट्स के लिए स्ट्रिंग आकार को सीमित करने के प्रतिबंध, यह एक समस्या थी जो मुझे वास्तव में टर्बो पास्कल के साथ थी)।
  • स्ट्रिंग हेरफेर का कार्यान्वयन बहुत ही सरल लाइब्रेरी फ़ंक्शन का एक मुट्ठी भर है
  • तार के मुख्य उपयोग के लिए कुशल: निरंतर पाठ एक ज्ञात शुरुआत (उपयोगकर्ता के लिए ज्यादातर संदेश) से क्रमिक रूप से पढ़ा जाता है।
  • टर्मिनेटिंग जीरो भी अनिवार्य नहीं है, बाइट्स का एक गुच्छा की तरह चार्ट में हेरफेर करने के सभी आवश्यक उपकरण उपलब्ध हैं। C में सरणी इनिशियलाइज़ेशन करते समय, आप NUL टर्मिनेटर से भी बच सकते हैं। बस सही आकार निर्धारित करें। char a[3] = "foo";मान्य C है (C ++ नहीं) और अंतिम शून्य को a में नहीं रखेगा।
  • "सब कुछ फ़ाइल है" के यूनिक्स बिंदु के साथ सुसंगत है, जिसमें "फाइलें" शामिल हैं, जिसमें स्टड, स्टडआउट जैसी कोई आंतरिक लंबाई नहीं है। आपको याद रखना चाहिए कि खुले पढ़ना और लिखना आदिम बहुत कम स्तर पर लागू किया जाता है। वे लाइब्रेरी कॉल नहीं हैं, लेकिन सिस्टम कॉल। और उसी API का उपयोग बाइनरी या टेक्स्ट फ़ाइलों के लिए किया जाता है। फ़ाइल रीडिंग प्राइमिटिव्स को एक बफर एड्रेस और एक आकार मिलता है और नए आकार को वापस करता है। और आप स्ट्रिंग को लिखने के लिए बफर के रूप में उपयोग कर सकते हैं। दूसरे प्रकार के स्ट्रिंग प्रतिनिधित्व का उपयोग करने से आप आसानी से आउटपुट के लिए बफर के रूप में शाब्दिक स्ट्रिंग का उपयोग नहीं कर सकते हैं, या आपको इसे कास्टिंग करते समय बहुत ही अजीब व्यवहार करना होगा char*। अर्थात् स्ट्रिंग के पते को वापस नहीं करना है, बल्कि वास्तविक डेटा को वापस करना है।
  • फाइल में जगह से पढ़े गए पाठ डेटा में हेरफेर करना बहुत आसान है, बिना बफर की बेकार कॉपी के, बस सही स्थानों पर शून्य डालें (अच्छी तरह से, आधुनिक सी के साथ वास्तव में नहीं, क्योंकि डबल उद्धृत स्ट्रिंग्स हैं कॉस्ट चार सरणियां अब आम तौर पर गैर-परिवर्तनीय डेटा में रखी जाती हैं खंड)।
  • जो कुछ भी आकार के कुछ अंतर मूल्यों prepending संरेखण मुद्दों का तात्पर्य होगा। प्रारंभिक लंबाई को संरेखित किया जाना चाहिए, लेकिन ऐसा करने का कोई कारण नहीं है कि वर्णों के लिए प्रोटोकॉल (और फिर से, स्ट्रिंग के संरेखण को मजबूर करने पर उन्हें बाइट्स के रूप में इलाज करते समय समस्या होगी)।
  • लंबाई को लगातार शाब्दिक स्ट्रिंग्स (साइज़ोफ़) के लिए संकलन समय पर जाना जाता है। तो क्यों कोई इसे वास्तविक डेटा के लिए याददाश्त में रखना चाहता है?
  • एक तरह से C (लगभग) हर किसी के रूप में कर रहा है, तार को char के सरणियों के रूप में देखा जाता है। चूंकि सरणी की लंबाई C द्वारा प्रबंधित नहीं की जाती है, इसलिए यह तार्किक लंबाई है जिसे स्ट्रिंग्स के लिए भी प्रबंधित नहीं किया गया है। केवल आश्चर्यजनक बात यह है कि 0 आइटम अंत में जोड़ा गया है, लेकिन दोहरे उद्धरण चिह्नों के बीच स्ट्रिंग टाइप करते समय यह केवल मुख्य भाषा स्तर पर है। उपयोगकर्ता पूरी तरह से गुजरने वाले स्ट्रिंग हेरफेर फ़ंक्शन को कॉल कर सकते हैं, या यहां तक ​​कि इसके बजाय सादा मेमोपी का उपयोग कर सकते हैं। SZ सिर्फ एक सुविधा है। अधिकांश अन्य भाषाओं में सरणी की लंबाई प्रबंधित की जाती है, यह तार्किक है जो स्ट्रिंग के लिए समान है।
  • आधुनिक समय में वैसे भी 1 बाइट चरित्र सेट पर्याप्त नहीं हैं और आपको अक्सर एन्कोडेड यूनिकोड स्ट्रिंग्स से निपटना पड़ता है जहां वर्णों की संख्या बाइट्स की संख्या से बहुत भिन्न होती है। तात्पर्य यह है कि उपयोगकर्ता शायद "सिर्फ आकार" से अधिक चाहते हैं, लेकिन अन्य informations भी। जानकारी के अन्य उपयोगी टुकड़ों के संबंध में लंबाई रखने से कुछ भी नहीं (विशेष रूप से कोई प्राकृतिक जगह उन्हें स्टोर करने के लिए) का उपयोग करें।

उस ने कहा, दुर्लभ मामले में शिकायत करने की कोई जरूरत नहीं है जहां मानक सी तार वास्तव में अक्षम हैं। लिब उपलब्ध हैं। यदि मैंने उस प्रवृत्ति का पालन किया है, तो मुझे शिकायत करनी चाहिए कि मानक सी में कोई रेगेक्स समर्थन फ़ंक्शन शामिल नहीं है ... लेकिन वास्तव में हर कोई जानता है कि यह एक वास्तविक समस्या नहीं है क्योंकि उस उद्देश्य के लिए पुस्तकालय उपलब्ध हैं। तो जब स्ट्रिंग हेरफेर दक्षता चाहता है, तो बस्ट्रिंग जैसी लाइब्रेरी का उपयोग क्यों न करें ? या यहां तक ​​कि सी ++ तार?

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

लेकिन D सरणियाँ C सरणियों की तुलना में बहुत समृद्ध हैं। स्थैतिक सरणियों के मामले में लंबाई को रन-टाइम पर जाना जाता है, इसलिए लंबाई को स्टोर करने की कोई आवश्यकता नहीं है। संकलक के पास संकलन समय पर है। डायनेमिक सरणियों के मामले में, लंबाई उपलब्ध है लेकिन डी प्रलेखन यह नहीं बताता है कि यह कहाँ रखा गया है। हम सभी जानते हैं, संकलक इसे कुछ रजिस्टर में रखने के लिए चुन सकता है, या वर्ण डेटा से बहुत दूर संग्रहित किसी चर में।

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

केवल एक चीज जिसने मुझे कुछ हद तक निराश किया है, वह यह है कि तार को utf-8 माना जाता है, लेकिन लंबाई स्पष्ट रूप से अभी भी कई बाइट्स (कम से कम यह मेरे कंपाइलर gdc पर सच है) मल्टी-बाइट चार्ट का उपयोग करते समय भी लौटती है। यदि यह संकलक बग है या उद्देश्य से यह मेरे लिए अस्पष्ट है। (ठीक है, मुझे शायद पता चला है कि क्या हुआ था। डी कंपाइलर को अपने स्रोत यूएफ -8 का उपयोग करने के लिए कहने के लिए आपको शुरुआत में कुछ बेवकूफ बाइट ऑर्डर मार्क लगाने होंगे। मैं बेवकूफ इसलिए लिखता हूं क्योंकि मुझे ऐसा नहीं करने वाले संपादक का पता है, खासकर यूटीएफ के लिए- 8 जो ASCII संगत माना जाता है)।


7
... जारी है ... आपके कई बिंदु मुझे लगता है कि सिर्फ सादे गलत हैं, अर्थात "सब कुछ एक फ़ाइल है" तर्क। फाइलें अनुक्रमिक पहुंच हैं, सी स्ट्रिंग नहीं हैं। न्यूनतम उपसर्ग के साथ लंबाई का उपसर्ग भी किया जा सकता है। यहां एकमात्र उचित तर्क है कि छोटे (यानी 8 बिट) हार्डवेयर पर 32 बिट उपसर्गों का प्रबंधन करने की कोशिश की जा रही है; मुझे लगता है कि लंबाई का आकार यह कहकर हल किया जा सकता है कि कार्यान्वयन द्वारा निर्धारित किया जाता है। आखिर std::basic_stringऐसा क्या है।
बिली ओनली

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

2
@ बिली ओनली: यह सिर्फ सच नहीं है, कोर क्या है और लाइब्रेरी क्या है, इसका उपयोग करता है। सबसे बड़ा बिंदु यह है कि जब सी का उपयोग ओएस को लागू करने के लिए किया जाता है। उस स्तर पर कोई पुस्तकालय उपलब्ध नहीं हैं। सी का उपयोग अक्सर एम्बेडेड संदर्भों में या प्रोग्रामिंग उपकरणों के लिए भी किया जाता है जहां आपके पास अक्सर एक ही तरह के प्रतिबंध होते हैं। कई मामलों में जोस को सी का इस्तेमाल शायद अब नहीं करना चाहिए: "ठीक है, आप इसे कंसोल पर चाहते हैं? क्या आपके पास कंसोल है? नहीं? बहुत बुरा ..."
क्राइस

5
@ बिली ", ऑपरेटिंग सिस्टम को लागू करने वाले C प्रोग्रामर के .01% के लिए ठीक है।" अन्य प्रोग्रामर बढ़ोतरी ले सकते हैं। C को एक ऑपरेटिंग सिस्टम लिखने के लिए बनाया गया था।
डैनियल सी। सोबरल

5
क्यों? क्योंकि यह कहता है कि यह एक सामान्य उद्देश्य की भाषा है? क्या यह कहता है कि जो लोग इसे लिखते थे वे इसे बनाते समय क्या कर रहे थे? अपने जीवन के पहले कुछ वर्षों के लिए इसका क्या उपयोग किया गया था? तो, यह क्या है जो यह कहता है कि मुझसे असहमत है? यह एक ऑपरेटिंग सिस्टम लिखने के लिए बनाई गई एक सामान्य उद्देश्य की भाषा है । क्या इससे इनकार है?
डैनियल सी। सोबरल

61

मुझे लगता है, इसके ऐतिहासिक कारण हैं और विकिपीडिया में यह पाया गया है :

उस समय C (और जिन भाषाओं से इसे प्राप्त किया गया था) विकसित किए गए थे, मेमोरी बेहद सीमित थी, इसलिए एक स्ट्रिंग की लंबाई को स्टोर करने के लिए ओवरहेड के केवल एक बाइट का उपयोग करना आकर्षक था। उस समय का एकमात्र लोकप्रिय विकल्प, जिसे आमतौर पर "पास्कल स्ट्रिंग" कहा जाता था (हालांकि इसका उपयोग BASIC के शुरुआती संस्करणों द्वारा भी किया गया था), स्ट्रिंग की लंबाई को संग्रहीत करने के लिए एक प्रमुख बाइट का उपयोग करता था। यह स्ट्रिंग को एनयूएल को शामिल करने की अनुमति देता है और लंबाई को खोजने के लिए केवल एक मेमोरी एक्सेस (ओ (1) (निरंतर) समय) की आवश्यकता होती है। लेकिन एक बाइट लंबाई को 255 तक सीमित करता है। यह लंबाई सीमा सी स्ट्रिंग के साथ समस्याओं की तुलना में कहीं अधिक प्रतिबंधात्मक थी, इसलिए सामान्य रूप से सी स्ट्रिंग जीत गई।


2
@ मंटू हम्म ... संगतता?
खटिक

19
@ मंटू: क्योंकि यह मौजूदा सी और सी ++ कोड की स्मारकीय मात्रा को तोड़ देगा।
बिली ओनेल

10
@ मंटू: प्रतिमान आते हैं और चले जाते हैं, लेकिन विरासत कोड हमेशा के लिए है। सी के किसी भी भविष्य के संस्करण को 0-समाप्त स्ट्रिंग्स का समर्थन करना जारी रखना होगा, अन्यथा विरासत कोड के 30+ वर्ष के मूल्य को फिर से लिखना होगा (जो होने वाला नहीं है)। और जब तक पुराना रास्ता उपलब्ध है, तब तक लोग इसका उपयोग करना जारी रखेंगे, क्योंकि वे परिचित हैं।
जॉन बोडे

8
@ मंटू: मेरा विश्वास करो, कभी-कभी मैं चाहता हूं कि मैं कर सकता हूं। लेकिन मैं अभी भी पास्कल स्ट्रिंग्स पर 0-टर्मिनेटेड स्ट्रिंग्स पसंद करूंगा।
जॉन बोडे

2
विरासत के बारे में बात करें ... C ++ स्ट्रिंग्स को अब NUL- टर्मिनेट किया जाना अनिवार्य है।
जिम बेल्टर

32

Calavera सही है , लेकिन जैसा कि लोगों को उसकी बात समझ में नहीं आ रही है, मैं कुछ कोड उदाहरण प्रदान करूंगा।

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

यदि C के पास एक stringप्रकार है, जैसे, intया char, यह एक प्रकार होगा जो किसी रजिस्टर में या स्टैक में फिट नहीं होता है, और इसे किसी भी तरह से हैंडल करने के लिए मेमोरी आवंटन (इसके सभी समर्थन ढांचे के साथ) की आवश्यकता होगी। जिनमें से सभी सी के मूल सिद्धांतों के खिलाफ जाते हैं।

तो, सी में एक स्ट्रिंग है:

char s*;

तो, चलिए मान लेते हैं कि यह लंबाई-उपसर्ग थे। आइए कोड लिखने के लिए दो तारों को सम्मिलित करें:

char* concat(char* s1, char* s2)
{
    /* What? What is the type of the length of the string? */
    int l1 = *(int*) s1;
    /* How much? How much must I skip? */
    char *s1s = s1 + sizeof(int);
    int l2 = *(int*) s2;
    char *s2s = s2 + sizeof(int);
    int l3 = l1 + l2;
    char *s3 = (char*) malloc(l3 + sizeof(int));
    char *s3s = s3 + sizeof(int);
    memcpy(s3s, s1s, l1);
    memcpy(s3s + l1, s2s, l2);
    *(int*) s3 = l3;
    return s3;
}

एक स्ट्रिंग को परिभाषित करने के लिए एक अन्य विकल्प एक संरचना का उपयोग किया जाएगा:

struct {
  int len; /* cannot be left implementation-defined */
  char* buf;
}

इस बिंदु पर, सभी स्ट्रिंग हेरफेर के लिए दो आवंटन की आवश्यकता होगी, जो व्यवहार में है, इसका मतलब है कि आप किसी भी हैंडलिंग को करने के लिए लाइब्रेरी से गुजरेंगे।

अजीब बात है ... की तरह structs कि ऐसा सी में मौजूद हैं! वे केवल उपयोगकर्ता को संभालने के लिए आपके दिन-प्रतिदिन के प्रदर्शन संदेशों के लिए उपयोग नहीं किए जाते हैं।

तो, यहाँ बिंदु Calavera बना रहा है: C में कोई स्ट्रिंग प्रकार नहीं है । इसके साथ कुछ भी करने के लिए, आपको एक पॉइंटर लेना होगा और इसे पॉइंटर के रूप में दो अलग-अलग प्रकारों में डिकोड करना होगा, और फिर यह बहुत प्रासंगिक हो जाएगा कि स्ट्रिंग का आकार क्या है, और इसे केवल "कार्यान्वयन परिभाषित" के रूप में नहीं छोड़ा जा सकता है।

अब, C किसी भी तरह से मेमोरी को संभाल सकता है, और memलाइब्रेरी (इन <string.h>, सम!) में फ़ंक्शंस सभी टूलिंग प्रदान करता है जो आपको मेमोरी को पॉइंटर और साइज़ की एक जोड़ी के रूप में संभालने की आवश्यकता होती है। सी में तथाकथित "स्ट्रिंग्स" सिर्फ एक उद्देश्य के लिए बनाए गए थे: एक ऑपरेटिंग सिस्टम को लिखने के संदर्भ में संदेश दिखा रहा था जिसका उद्देश्य टर्मिनलों के लिए था। और, उसके लिए, शून्य समाप्ति पर्याप्त है।


2
1. +1। 2. जाहिर है कि यदि लंबाई उपसर्गों का उपयोग करके भाषा का डिफ़ॉल्ट व्यवहार किया गया होता, तो उस आसान को बनाने के लिए अन्य चीजें भी होतीं। उदाहरण के लिए, आपके सभी कलाकार वहाँ strlenऔर उसके बजाय दोस्तों को कॉल करके छिप गए होंगे । जैसा कि "इसे कार्यान्वयन तक छोड़ने" के साथ समस्या है, आप कह सकते हैं कि उपसर्ग जो कुछ भी shortहै वह लक्ष्य बॉक्स पर है। तब आपकी सभी कास्टिंग अभी भी काम करेगी। 3. मैं दिन भर में आने वाले परिदृश्यों के साथ आ सकता हूं जो एक या दूसरे सिस्टम को खराब करते हैं।
बिली ओनेल

5
@ बिली पुस्तकालय की बात काफी हद तक सही है, इस तथ्य से अलग कि सी को न्यूनतम या किसी पुस्तकालय के उपयोग के लिए नहीं बनाया गया था। उदाहरण के लिए, प्रोटोटाइप का उपयोग आम जल्दी नहीं था। उपसर्ग कहना shortप्रभावी रूप से स्ट्रिंग के आकार को सीमित करता है, जो एक चीज लगती है जो वे उत्सुक नहीं थे। स्वयं, 8-बिट्स बेसिक और पास्कल स्ट्रिंग्स, फिक्स्ड-साइज़ कोबोल स्ट्रिंग्स और इसी तरह की चीजों के साथ काम करने के बाद, असीमित आकार के सी स्ट्रिंग्स का बहुत बड़ा प्रशंसक बन गया। आजकल, 32-बिट आकार किसी भी व्यावहारिक स्ट्रिंग को संभालेंगे, लेकिन उन बाइट्स को जल्दी से जोड़ना समस्याग्रस्त था।
डेनियल सी। सोबरल

1
@ बिली: सबसे पहले, डैनियल को धन्यवाद ... आप समझ रहे हैं कि मुझे क्या मिल रहा है। दूसरा, बिली, मुझे लगता है कि आप अभी भी उस बिंदु को याद कर रहे हैं जो यहां बनाया जा रहा है। मैं एक के लिए उनकी लंबाई के साथ स्ट्रिंग डेटा-प्रकारों के प्रीफ़िक्सिंग के पेशेवरों और विपक्षों पर बहस नहीं कर रहा हूं । मैं जो कह रहा हूं, और डैनियल ने बहुत स्पष्ट रूप से जोर दिया है, वह यह है कि सी के कार्यान्वयन में एक निर्णय था जो उस तर्क को बिल्कुल भी नहीं संभाल सकता था । जहां तक ​​मूल भाषा का सवाल है, स्ट्रिंग्स मौजूद नहीं है। स्ट्रिंगर्स को कैसे संभालना है, इसका निर्णय प्रोग्रामर पर छोड़ दिया जाता है ... और शून्य समाप्ति लोकप्रिय हो गई।
रॉबर्ट एस सियासीओ

1
मेरे द्वारा +1। एक और बात मैं जोड़ना चाहूंगा; एक संरचना जैसा कि आप प्रस्तावित करते हैं कि यह एक वास्तविक stringप्रकार की ओर एक महत्वपूर्ण कदम याद आती है : यह पात्रों के बारे में पता नहीं है। यह "चार" की एक सरणी है (मशीन लिंगो में एक "चार" उतना ही एक चरित्र है जितना एक "शब्द" है जिसे मनुष्य एक वाक्य में एक शब्द कहते हैं)। वर्णों की एक स्ट्रिंग एक उच्च-स्तरीय अवधारणा है, जिसे यदि आप एन्कोडिंग की धारणा पेश करते हैं , तो एक सरणी के शीर्ष पर लागू किया जा सकता है char
Frerich Raabe

2
@ डैनियल.सी.ब्राल: इसके अलावा, आपके द्वारा उल्लेखित संरचना को दो आवंटन की आवश्यकता नहीं होगी। या तो इसका उपयोग करें क्योंकि आपके पास यह स्टैक पर है (इसलिए केवल bufएक आवंटन की आवश्यकता है), या struct string {int len; char buf[]};एक लचीली सरणी सदस्य के रूप में एक आवंटन के साथ पूरी चीज़ का उपयोग करें और आवंटित करें, और इसे एक के रूप में पास करें string*। (या struct string {int capacity; int len; char buf[]};स्पष्ट रूप से , स्पष्ट प्रदर्शन कारणों के लिए)
मूकिंग डक

20

स्पष्ट रूप से प्रदर्शन और सुरक्षा के लिए, आप एक स्ट्रिंग की लंबाई रखना चाहते हैं, जबकि आप बार-बार प्रदर्शन करने strlenया उस पर इसके बजाय इसके साथ काम कर रहे हैं । हालांकि, स्ट्रिंग सामग्री से ठीक पहले एक निश्चित स्थान में लंबाई को संग्रहीत करना एक अविश्वसनीय रूप से खराब डिजाइन है। जैसा कि जार्जन ने संजीत के जवाब पर टिप्पणियों में बताया, यह एक स्ट्रिंग के रूप में एक स्ट्रिंग की पूंछ का इलाज करता है, जो उदाहरण के लिए नई स्मृति को आवंटित किए बिना (या विफलता और त्रुटि से निपटने की संभावना को कम करने के बिना) जैसे बहुत सारे सामान्य ऑपरेशन करता है path_to_filenameया filename_to_extensionअसंभव है । और फिर निश्चित रूप से यह मुद्दा है कि कोई भी इस बात से सहमत नहीं हो सकता है कि स्ट्रिंग लंबाई क्षेत्र को कितने बाइट्स पर कब्जा करना चाहिए (बहुत बुरा "पीपल स्ट्रिंग")

प्रोग्रामर को यह बताने के लिए कि क्या / जहां / कैसे स्टोर करना है, का डिज़ाइन बहुत अधिक लचीला और शक्तिशाली है। लेकिन बेशक प्रोग्रामर को स्मार्ट होना है। सी मूर्खता को उन कार्यक्रमों के साथ दंडित करता है जो दुर्घटनाग्रस्त होते हैं, एक पड़ाव को पीसते हैं, या अपने दुश्मनों को जड़ देते हैं।


+1। लंबाई को स्टोर करने के लिए एक मानक स्थान रखना अच्छा होगा, हालांकि हम में से जो लोग लंबाई उपसर्ग जैसा कुछ चाहते हैं, उन्हें हर जगह "गोंद कोड" का टन नहीं लिखना होगा।
बिली ओनेल

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

13

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

चलो छद्म कोड में देखते हैं

function readString(string) // 1 parameter: 1 register or 1 stact entries
    pointer=addressOf(string) 
    while(string[pointer]!=CONTROL_CHAR) do
        read(string[pointer])
        increment pointer

कुल 1 रजिस्टर का उपयोग

मामला 2

 function readString(length,string) // 2 parameters: 2 register used or 2 stack entries
     pointer=addressOf(string) 
     while(length>0) do 
         read(string[pointer])
         increment pointer
         decrement length

कुल 2 रजिस्टर का इस्तेमाल किया

उस समय यह कम प्रतीत हो सकता है, लेकिन कोड और रजिस्टर में मितव्ययिता को देखते हुए (जो उस समय PREMIUM थे, जिस समय आप जानते हैं, वे पंच कार्ड का उपयोग करते हैं)। इस प्रकार तेज़ होना (जब प्रोसेसर की गति को kHz में गिना जा सकता है), यह "हैक" आसानी से रजिस्टर-कम प्रोसेसर के लिए बहुत अच्छा और पोर्टेबल था।

तर्क के लिए मैं 2 सामान्य स्ट्रिंग ऑपरेशन लागू करूंगा

stringLength(string)
     pointer=addressOf(string)
     while(string[pointer]!=CONTROL_CHAR) do
         increment pointer
     return pointer-addressOf(string)

जटिलता O (n) जहां ज्यादातर मामले में PASCAL स्ट्रिंग O (1) है क्योंकि स्ट्रिंग की लंबाई स्ट्रिंग संरचना से पूर्व-लंबित है (इसका मतलब यह भी होगा कि इस ऑपरेशन को पहले के चरण में ले जाना होगा)।

concatString(string1,string2)
     length1=stringLength(string1)
     length2=stringLength(string2)
     string3=allocate(string1+string2)
     pointer1=addressOf(string1)
     pointer3=addressOf(string3)
     while(string1[pointer1]!=CONTROL_CHAR) do
         string3[pointer3]=string1[pointer1]
         increment pointer3
         increment pointer1
     pointer2=addressOf(string2)
     while(string2[pointer2]!=CONTROL_CHAR) do
         string3[pointer3]=string2[pointer2]
         increment pointer3
         increment pointer1
     return string3

जटिलता O (n) और स्ट्रिंग की लंबाई का अनुमान लगाने से ऑपरेशन की जटिलता में बदलाव नहीं होगा, जबकि मैं मानता हूं कि इसमें 3% कम समय लगेगा।

दूसरी ओर, यदि आप PASCAL स्ट्रिंग का उपयोग करते हैं, तो आपको अपने API को खाता रजिस्टर लंबाई और बिट-एंडनेस में लेने के लिए फिर से डिज़ाइन करना होगा, PASCAL स्ट्रिंग को 255 char (0xFF) की सुप्रसिद्ध सीमा मिली, क्योंकि लंबाई 1 बाइट में संग्रहीत थी (8 बिट्स) ), और यह आप एक लंबी स्ट्रिंग (16 बिट्स -> कुछ भी) चाहते थे, आपको अपने कोड की एक परत में आर्किटेक्चर को ध्यान में रखना होगा, यदि आप लंबे स्ट्रिंग चाहते हैं तो ज्यादातर असंगत स्ट्रिंग एपीआई में इसका मतलब होगा।

उदाहरण:

एक फ़ाइल 8 बिट कंप्यूटर पर आपके पहले से तैयार स्ट्रिंग एपी के साथ लिखी गई थी और फिर उसे 32 बिट कंप्यूटर कहने पर पढ़ा जाना होगा, आलसी प्रोग्राम क्या विचार करेगा कि आपके 4bytes स्ट्रिंग की लंबाई है, फिर उस मेमोरी को आवंटित करें फिर उस कई बाइट्स को पढ़ने का प्रयास करें। एक और मामला एक x86 (बड़ा एंडियन) पर पीपीसी 32 बाइट स्ट्रिंग रीड (थोड़ा एंडियन) होगा, निश्चित रूप से यदि आप नहीं जानते कि एक दूसरे द्वारा लिखा गया है तो परेशानी होगी। 1 बाइट की लंबाई (0x00000001) 16777216 (0x0100000) बन जाएगी जो कि 1 बाइट स्ट्रिंग को पढ़ने के लिए 16 एमबी है। बेशक आप कहेंगे कि लोगों को एक मानक पर सहमत होना चाहिए, लेकिन 16 बिट यूनिकोड को भी थोड़ा और बड़ा समर्थन मिला।

बेशक सी के अपने मुद्दे भी होंगे लेकिन, यहां उठाए गए मुद्दों से बहुत कम प्रभावित होंगे।


2
@deemoowoor: कॉनैटैट: O(m+n)अशक्त तार के साथ, O(n)हर जगह विशिष्ट। हर जगह और O(n)कहीं अशक्त तारों के साथ लंबाई O(1)। शामिल हों: O(n^2)nullterm तार के साथ, O(n)हर जगह। कुछ ऐसे मामले हैं जहाँ अशक्त तार अधिक कुशल होते हैं (यानी पॉइंटर मामले में सिर्फ एक जोड़ते हैं), लेकिन कॉनकैट और लंबाई अब तक के सबसे आम ऑपरेशन हैं (स्वरूपण, फ़ाइल आउटपुट, कंसोल डिस्प्ले आदि के लिए लंबाई कम से कम आवश्यक है) । यदि आप लंबाई को बढ़ा-चढ़ाकर O(n)बताते हैं , तो आपने केवल इतना ही कहा है कि लंबाई को स्ट्रिंग के साथ संग्रहीत किया जाना चाहिए।
बिली ओनेल

1
मैं मानता हूं कि आज के कोड में इस प्रकार का स्ट्रिंग अक्षम है और त्रुटि के लिए प्रवण है, लेकिन उदाहरण के लिए कंसोल डिस्प्ले को वास्तव में इसे कुशलता से प्रदर्शित करने के लिए स्ट्रिंग की लंबाई पता करने की आवश्यकता नहीं है, फ़ाइल आउटपुट को वास्तव में स्ट्रिंग के बारे में जानने की आवश्यकता नहीं है लंबाई (केवल जाने पर क्लस्टर आवंटित करना), और इस समय स्ट्रिंग स्वरूपण ज्यादातर मामले में एक निश्चित स्ट्रिंग लंबाई पर किया गया था। वैसे भी आप बुरा कोड लिख रहे होंगे अगर आप C में O (n ^ 2) जटिलता रखते हैं, तो मुझे पूरा यकीन है कि मैं O (n) जटिलता में एक लिख सकता हूं
dvhh

1
@dvhh: मैंने n ^ 2 नहीं कहा - मैंने कहा कि m + n - यह अभी भी रैखिक है, लेकिन आपको समवर्ती करने के लिए मूल स्ट्रिंग के अंत की तलाश करने की आवश्यकता है, जबकि लंबाई के साथ उपसर्ग कोई मांग नहीं है आवश्यक है। (यह वास्तव में रेखीय समय की आवश्यकता लंबाई का एक और परिणाम है)
बिली ओनेल

1
@ बिली ओनली: मात्र जिज्ञासा से मैंने स्ट्रिंग हेरफेर फ़ंक्शन कॉल के लिए अपने वर्तमान सी प्रोजेक्ट (कोड की लगभग 50000 लाइनें) पर एक grep किया। strlen 101, strcpy और वैरिएंट (strncpy, strlcpy): 85 (मेरे पास संदेश के लिए कई शाब्दिक तार का उपयोग किया जाता है, प्रतियाँ कॉपी की जाती हैं), strcmp: 56, strcat: 13 (और 6 stratcat को कॉल करने के लिए शून्य लंबाई स्ट्रिंग के लिए संघनन) । मैं मानता हूं कि एक लंबाई उपसर्ग स्ट्रिपअप कॉल को strlen करने के लिए होगा, लेकिन strcpy या strcmp के लिए नहीं (शायद अगर strcmp API सामान्य उपसर्ग का उपयोग नहीं करता है)। उपरोक्त टिप्पणियों के बारे में सबसे दिलचस्प बात यह है कि स्ट्रैट बहुत दुर्लभ है।
क्राइस

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

9

कई मायनों में, सी आदिम था। और मैं इसे प्यार करता था।

यह असेंबली लैंग्वेज से एक कदम ऊपर था, आपको लगभग उसी भाषा के साथ प्रदर्शन करना था जो लिखना और बनाए रखना बहुत आसान था।

अशक्त टर्मिनेटर सरल है और उसे भाषा द्वारा किसी विशेष समर्थन की आवश्यकता नहीं है।

पीछे मुड़कर देखें, तो यह सुविधाजनक नहीं लगता। लेकिन मैंने 80 के दशक में असेंबली भाषा का उपयोग किया और यह उस समय बहुत सुविधाजनक था। मुझे लगता है कि सॉफ़्टवेयर लगातार विकसित हो रहा है, और प्लेटफ़ॉर्म और टूल लगातार और अधिक परिष्कृत होते हैं।


मैं यह नहीं देखता कि किसी भी चीज की तुलना में अशक्त समाप्त होने के बारे में क्या आदिम है। पास्कल सी की भविष्यवाणी करता है और यह लंबाई पूर्वसर्ग का उपयोग करता है। निश्चित रूप से, यह प्रति स्ट्रिंग 256 वर्णों तक सीमित था, लेकिन केवल 16 बिट क्षेत्र का उपयोग करने से अधिकांश मामलों में समस्या हल हो जाती थी।
बिली ओनेल

यह तथ्य कि यह वर्णों की संख्या को सीमित करता है, ठीक उसी प्रकार के मुद्दे हैं जिनके बारे में आपको ऐसा करने के बारे में सोचने की आवश्यकता है। हां, आप इसे अधिक समय तक बना सकते हैं, लेकिन वापस तो बाइट्स मायने रखती हैं। और क्या 16-बिट क्षेत्र सभी मामलों के लिए काफी लंबा है? C'mon, आपको यह स्वीकार करना होगा कि एक शून्य-समापन वैचारिक रूप से आदिम है।
जोनाथन वुड

10
या तो आप स्ट्रिंग की लंबाई को सीमित करते हैं या आप सामग्री (कोई शून्य वर्ण) को सीमित करते हैं, या आप 4 से 8 बाइट की गिनती के अतिरिक्त ओवरहेड को स्वीकार करते हैं। कोई मुफ्त भोजन नहीं है। स्थापना के समय अशक्त समाप्त स्ट्रिंग का सही अर्थ है। असेंबली में मैंने कभी-कभी एक स्ट्रिंग के अंत को चिह्नित करने के लिए एक चरित्र के शीर्ष बिट का उपयोग किया, यहां तक ​​कि एक और बाइट को बचाते हुए!
मार्क रैनसम

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

8

एक पल के लिए मान लें कि C ने पास्कल मार्ग को स्ट्रिंग्स द्वारा कार्यान्वित किया, उन्हें लंबाई द्वारा प्रीफ़िक्स करते हुए: क्या एक 7 char long string एक ही DATA TYPE है जो 3-char string के रूप में है? यदि उत्तर हाँ है, तो जब मैं पूर्व को बाद में सौंपता हूं तो संकलक किस तरह का कोड उत्पन्न करना चाहिए? क्या तार को काट दिया जाना चाहिए, या स्वचालित रूप से आकार बदल दिया जाना चाहिए? यदि आकार बदला जाता है, तो क्या उस ऑपरेशन को एक ताला द्वारा संरक्षित किया जाना चाहिए ताकि यह धागा सुरक्षित हो सके? C दृष्टिकोण पक्ष ने इन सभी मुद्दों को आगे बढ़ाया, जैसे कि यह :)


2
Err .. नहीं, यह नहीं था। C दृष्टिकोण 7 char लंबी स्ट्रिंग को 7 char लंबी स्ट्रिंग को निर्दिष्ट करने की अनुमति नहीं देता है।
बिली ओनेल

@ बिली ओनली: क्यों नहीं? जहां तक ​​मैं इसे इस मामले में समझता हूं, सभी तार एक ही डेटा प्रकार (चार *) हैं, इसलिए लंबाई मायने नहीं रखती है। पास्कल के विपरीत। लेकिन वह पास्कल की एक सीमा थी, बजाय एक समस्या के जो लम्बे-लम्बे तारों के साथ थी।
ओलिवर मेसन

4
@ बिली: मुझे लगता है कि आपने सिर्फ क्रिस्टियन की बात को बहाल किया है। C इन मुद्दों से बिल्कुल नहीं निपटता है। आप अभी भी सी के संदर्भ में सोच रहे हैं वास्तव में एक स्ट्रिंग की धारणा है। यह सिर्फ एक पॉइंटर है, इसलिए आप इसे अपनी इच्छानुसार असाइन कर सकते हैं।
रॉबर्ट एस सियासीओ

2
यह ** मैट्रिक्स की तरह है: "कोई स्ट्रिंग नहीं है"।
रॉबर्ट एस सियासीओ

1
@ कैलावेरा: मैं नहीं देखता कि कैसे कुछ भी साबित होता है। आप इसे उसी तरह से हल कर सकते हैं जैसे कि लंबाई उपसर्ग ... यानी असाइनमेंट को बिल्कुल भी अनुमति न दें।
बिली ओनेल

8

किसी तरह मैंने समझा कि सी में लंबाई-उपसर्गों के तार के लिए कोई संकलक समर्थन नहीं है। निम्न उदाहरण से पता चलता है, कम से कम आप अपनी खुद की सी स्ट्रिंग लाइब्रेरी शुरू कर सकते हैं, जहां स्ट्रिंग की लंबाई संकलित समय पर गिना जाता है, इस तरह से एक निर्माण के साथ।

#define PREFIX_STR(s) ((prefix_str_t){ sizeof(s)-1, (s) })

typedef struct { int n; char * p; } prefix_str_t;

int main() {
    prefix_str_t string1, string2;

    string1 = PREFIX_STR("Hello!");
    string2 = PREFIX_STR("Allows \0 chars (even if printf directly doesn't)");

    printf("%d %s\n", string1.n, string1.p); /* prints: "6 Hello!" */
    printf("%d %s\n", string2.n, string2.p); /* prints: "48 Allows " */

    return 0;
}

हालांकि, यह कोई समस्या नहीं है, क्योंकि आपको विशेष रूप से उस स्ट्रिंग पॉइंटर को मुक्त करने के लिए सावधान रहने की आवश्यकता है और जब इसे सांख्यिकीय रूप से आवंटित किया जाता है (शाब्दिक charसरणी)।

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

बेशक ऐसा लगता है कि शून्य-टर्मिनेटेड स्ट्रिंग्स के साथ काम करना अनुशंसित अभ्यास था, क्योंकि सामान्य रूप से मानक पुस्तकालय तर्क के रूप में स्ट्रिंग की लंबाई नहीं लेता है, और चूंकि लंबाई निकालने के लिए सीधा कोड नहीं है char * s = "abc", जैसा कि मेरा उदाहरण दिखाता है।


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

1
यह सच है। तो बड़ी समस्या यह है कि सादे पुराने शून्य-समाप्त स्ट्रिंग्स की तुलना में स्ट्रिंग मापदंडों के साथ इंटरफेस प्रदान करने का कोई बेहतर मानक तरीका नहीं है। मैं अभी भी दावा करता हूं, ऐसे पुस्तकालय हैं जो पॉइंटर-लंबाई जोड़े में भोजन का समर्थन करते हैं (अच्छी तरह से, कम से कम आप सी ++ स्टीडी :: उनके साथ स्ट्रिंग का निर्माण कर सकते हैं)।
पायरी जहकोला

2
यहां तक ​​कि अगर आप एक लंबाई स्टोर करते हैं, तो भी आपको कभी-कभी एम्बेडेड नल के साथ तार की अनुमति नहीं देनी चाहिए। यह बुनियादी सामान्य ज्ञान है। यदि आपके डेटा में नल हो सकते हैं, तो आपको उन कार्यों के साथ कभी भी इसका उपयोग नहीं करना चाहिए जो स्ट्रिंग की अपेक्षा करते हैं।
R .. गिटहब स्टॉप हेल्पिंग ICE

1
@ सुपरकैट: सुरक्षा के दृष्टिकोण से मैं उस अतिरेक का स्वागत करूंगा। अन्यथा अज्ञानी (या नींद से वंचित) प्रोग्रामर अंत बाइनरी डेटा और तार श्रृंखलाबद्ध और उन्हें चीजें हैं जो उम्मीद में गुजर [अशक्त-समाप्त] तार ...
आर .. GitHub बंद की मदद बर्फ

1
@ आर ..: जबकि विधिवत् शून्य स्ट्रिंग की अपेक्षा करने वाले char*तरीके आम तौर पर एक की उम्मीद करते हैं , कई तरीके जो शून्य समाप्ति की उम्मीद नहीं करते हैं, वे भी उम्मीद करते हैं char*। प्रकारों को अलग करने का एक अधिक महत्वपूर्ण लाभ यूनिकोड व्यवहार से संबंधित होगा। स्ट्रिंग को लागू करने के लिए स्ट्रिंग कार्यान्वयन के लिए यह सार्थक हो सकता है कि क्या तार को कुछ प्रकार के वर्णों के लिए जाना जाता है, या उन्हें शामिल नहीं करने के लिए जाना जाता है [जैसे कि मिलियन-वर्ण स्ट्रिंग में 999,990 वां कोड बिंदु खोजना, जिसमें शामिल नहीं होने के लिए जाना जाता है मूल बहुभाषी विमान से परे किसी भी वर्ण में परिमाण के क्रम तेजी से होंगे ...
सुपरकैट

6

"यहां तक ​​कि एक 32 बिट मशीन पर, यदि आप स्ट्रिंग को उपलब्ध स्मृति के आकार की अनुमति देते हैं, तो एक लंबाई उपसर्ग स्ट्रिंग एक शून्य समाप्त स्ट्रिंग की तुलना में केवल तीन बाइट्स व्यापक है।"

पहले, अतिरिक्त 3 बाइट्स शॉर्ट स्ट्रिंग्स के लिए काफी उपरि हो सकते हैं। विशेष रूप से, एक शून्य-लंबाई वाली स्ट्रिंग अब अधिक मेमोरी लेती है। हम में से कुछ 64-बिट मशीनों का उपयोग कर रहे हैं, इसलिए हमें शून्य-लंबाई स्ट्रिंग को संग्रहीत करने के लिए या तो 8 बाइट्स की आवश्यकता होती है, या स्ट्रिंग प्रारूप प्लेटफ़ॉर्म का समर्थन करने वाले सबसे लंबे तारों से सामना नहीं कर सकता है।

इससे निपटने के लिए संरेखण मुद्दे भी हो सकते हैं। मान लीजिए कि मेरे पास 7 स्ट्रिंग्स वाली मेमोरी है, जैसे "सोलो \ _second \ 0 \ 0four \ 0five \ 0 \ 0seventh"। दूसरा स्ट्रिंग ऑफसेट 5 से शुरू होता है। हार्डवेयर के लिए आवश्यक हो सकता है कि 32-बिट पूर्णांकों को एक पते पर संरेखित किया जाए जो 4 से अधिक है, इसलिए आपको पैडिंग को जोड़ना होगा, ओवरहेड को और भी अधिक बढ़ाना होगा। सी प्रतिनिधित्व तुलना में बहुत स्मृति-कुशल है। (मेमोरी-दक्षता अच्छी है; यह उदाहरण के लिए कैश प्रदर्शन में मदद करता है।)


मेरा मानना ​​है कि मैंने इस प्रश्न में सभी को संबोधित किया। हाँ, x64 प्लेटफार्मों पर एक 32 बिट उपसर्ग सभी संभव तार फिट नहीं कर सकता है। दूसरी ओर, आप कभी भी एक स्ट्रिंग नहीं चाहते हैं जो एक शून्य समाप्त स्ट्रिंग के रूप में बड़ी है, क्योंकि कुछ भी करने के लिए आपको लगभग 4 बिलियन बाइट्स की जांच करनी होगी जो लगभग हर ऑपरेशन के लिए आप इसे करना चाहते हैं। इसके अलावा, मैं यह नहीं कह रहा हूं कि अशक्त समाप्त होने वाले तार हमेशा बुरे होते हैं - यदि आप इन ब्लॉक संरचनाओं में से एक का निर्माण कर रहे हैं और आपके विशिष्ट अनुप्रयोग को इस तरह के निर्माण से अलग किया गया है, तो इसके लिए जाएं। मैं बस भाषा के डिफ़ॉल्ट व्यवहार की कामना करता हूं।
बिली ओनेल

2
मैंने आपके प्रश्न के उस हिस्से को उद्धृत किया क्योंकि मेरे विचार में यह दक्षता के मुद्दे से कम था। स्मृति आवश्यकताओं को दोगुना या चौगुना करना (क्रमशः 16-बिट और 32-बिट पर) एक बड़ी प्रदर्शन लागत हो सकती है। लंबे तार धीमे हो सकते हैं, लेकिन कम से कम वे समर्थित हैं और अभी भी काम करते हैं। मेरे अन्य बिंदु, संरेखण के बारे में, आप बिल्कुल उल्लेख नहीं करते हैं।
Brangdon

संरेखण द्वारा निर्दिष्ट किया जा सकता है कि UCHAR_MAX से परे मानों को बाइट एक्सेस और बिट-शिफ्टिंग का उपयोग करके पैक और अनपैक्ड के रूप में व्यवहार करना चाहिए। एक उपयुक्त रूप से डिज़ाइन किया गया स्ट्रिंग प्रकार आवश्यक रूप से शून्य-टर्मिनेटेड स्ट्रिंग्स की तुलना में स्टोरेज दक्षता की पेशकश कर सकता है, जबकि अतिरिक्त मेमोरी ओवरहेड के लिए बफ़र्स पर सीमा-जाँच की भी अनुमति देता है (उपसर्ग में एक बिट का उपयोग यह कहने के लिए कि क्या बफर "पूर्ण" है; नहीं है और अंतिम बाइट गैर-शून्य है, जो बाइट शेष स्थान का प्रतिनिधित्व करेगा। यदि बफ़र पूर्ण नहीं है और अंतिम बाइट शून्य है, तो अंतिम 256 बाइट अप्रयुक्त होंगे, इसलिए ...
सुपरकैट

... कोई भी उस स्थान के भीतर अप्रयुक्त बाइट्स की सही संख्या को शून्य अतिरिक्त मेमोरी लागत के साथ स्टोर कर सकता है)। उपसर्गों के साथ काम करने की लागत स्ट्रिंग लंबाई को पारित करने के बिना (जैसे बफ़र्स को पता होगा कि वे कितने बड़े थे) तरीकों का उपयोग करने की क्षमता से ऑफसेट किया जाएगा।
सुपरकैट

4

नल समाप्ति तेजी से सूचक आधारित संचालन के लिए अनुमति देता है।


5
है ना? लंबाई उपसर्ग के साथ क्या "फास्ट पॉइंटर ऑपरेशन" काम नहीं करता है? इससे भी महत्वपूर्ण बात यह है कि, अन्य भाषाएं जो लंबाई पूर्वसर्ग का उपयोग करती हैं, C wrt स्ट्रिंग हेरफेर की तुलना में तेज होती हैं।
बिली ओनेल

12
@ बिली: लंबाई उपसर्गों के साथ, आप सिर्फ एक स्ट्रिंग पॉइंटर नहीं ले सकते हैं और इसमें 4 जोड़ सकते हैं, और उम्मीद करते हैं कि यह अभी भी एक वैध स्ट्रिंग हो, क्योंकि इसमें लंबाई उपसर्ग नहीं है (वैसे भी मान्य नहीं है)।
जोर्जेन सिगवार्डसन 20

3
@j_random_hacker: संभवतः ओ (एन) के बजाय एससिज़ स्ट्रिंग्स (ओ (एम + एन)) के लिए कॉनटैनेशन बहुत खराब है, और यहां सूचीबद्ध अन्य किसी भी ऑपरेशन की तुलना में कॉनकैट बहुत अधिक सामान्य है।
बिली ओनेल

3
वहाँ एक छोटे से छोटे ऑपरेशन है कि अशक्त समाप्त तार के साथ और अधिक महंगा हो जाता है strlen:। मैं कहूंगा कि यह एक छोटी सी खामी है।
११:१०

10
@ बिली ओनली: बाकी सभी भी रेगेक्स का समर्थन करते हैं। तो क्या ? पुस्तकालयों का उपयोग करें कि वे किस लिए बने हैं। सी अधिकतम दक्षता और अतिसूक्ष्मवाद के बारे में है, बैटरी शामिल नहीं है। सी उपकरण आपको बहुत आसानी से संरचनाओं का उपयोग करते हुए लंबाई के उपसर्गों को लागू करने की अनुमति देते हैं। और कुछ भी नहीं आप अपनी खुद की लंबाई और चार बफर के प्रबंधन के माध्यम से स्ट्रिंग हेरफेर कार्यक्रमों को लागू करने के लिए मना करते हैं। आमतौर पर मैं यही करता हूं कि जब मैं दक्षता चाहता हूं और सी का उपयोग करता हूं, तो मुट्ठी भर कार्यों को नहीं बुला रहा हूं जो एक चार बफर के अंत में एक शून्य की उम्मीद करता है, एक समस्या नहीं है।
क्रिश

4

एक बिंदु का अभी तक उल्लेख नहीं किया गया है: जब सी डिजाइन किया गया था, तो कई मशीनें थीं जहां एक 'चार' आठ बिट्स नहीं था (आज भी डीएसपी प्लेटफॉर्म हैं जहां यह नहीं है)। यदि कोई यह तय करता है कि तार लम्बाई-उपसर्ग होने हैं, तो किसी लम्बाई उपसर्ग के कितने 'चार' मूल्य का उपयोग करना चाहिए? दो का उपयोग करते हुए 8-बिट चार और 32-बिट एड्रेसिंग स्पेस के साथ मशीनों के लिए स्ट्रिंग की लंबाई पर एक कृत्रिम सीमा लागू होगी, जबकि 16-बिट चार और 16-बिट एड्रेसिंग स्पेस के साथ मशीनों पर जगह बर्बाद कर रही है।

यदि कोई मनमाने ढंग से लंबाई के तार को कुशलता से संग्रहीत करने की अनुमति देना चाहता था, और अगर 'चार' हमेशा 8-बिट होते थे, तो कोई - गति और कोड आकार में कुछ खर्च के लिए - एक योजना को परिभाषित कर सकता है एक समान संख्या के आधार पर उपसर्ग था। N, N / 2 बाइट्स लंबा होगा, एक स्ट्रिंग जो कि एक विषम मान N से उपसर्ग करता है और एक सम मूल्य M (पीछे की ओर पढ़ना) ((N-1) + M * char_max) / 2, आदि हो सकता है और इसके लिए किसी बफर की आवश्यकता होती है एक स्ट्रिंग रखने के लिए एक निश्चित मात्रा में स्थान देने का दावा करने से अधिकतम लंबाई को संभालने के लिए उस स्थान से पहले पर्याप्त बाइट्स की अनुमति मिलनी चाहिए। तथ्य यह है कि 'चार' हमेशा 8 बिट्स नहीं होता है, हालांकि, इस तरह की योजना को जटिल किया जाएगा, क्योंकि स्ट्रिंग की लंबाई रखने के लिए आवश्यक 'चार' की संख्या सीपीयू वास्तुकला के आधार पर अलग-अलग होगी।


उपसर्ग आसानी से कार्यान्वयन-परिभाषित आकार का हो सकता है, जैसा कि है sizeof(char)
बिली ओनेल

@ बिलियन: sizeof(char)एक है। हमेशा। एक उपसर्ग एक कार्यान्वयन-परिभाषित आकार हो सकता है, लेकिन यह अजीब होगा। इसके अलावा, यह जानने का कोई वास्तविक तरीका नहीं है कि "सही" आकार क्या होना चाहिए। यदि कोई 4-वर्ण स्ट्रिंग्स के बहुत सारे धारण कर रहा है, तो शून्य-पैडिंग 25% ओवरहेड लगाएगा, जबकि चार-बाइट की लंबाई उपसर्ग 100% ओवरहेड लगाएगा। इसके अलावा, चार-बाइट लंबाई उपसर्गों की पैकिंग और अनपैकिंग में लगने वाला समय शून्य बाइट के लिए 4-बाइट स्ट्रिंग्स को स्कैन करने की लागत से अधिक हो सकता है।
सुपरकैट

1
आह येस। आप सही हे। हालांकि उपसर्ग आसानी से चार के अलावा कुछ और हो सकता है। कुछ भी जो लक्ष्य प्लेटफ़ॉर्म वर्क आउट पर संरेखण आवश्यकताओं को ठीक करेगा। हालांकि मैं वहाँ नहीं जा रहा हूँ - मैंने पहले ही यह दलील दे दी है।
बिली ओनेल

मान लिया जाये कि तार की लंबाई-उपसर्ग के थे, हो सकता है एक ऐसा करने के लिए शायद sanest बात size_tउपसर्ग (स्मृति अपशिष्ट शापित हो, यह होगा sanest किसी भी संभावित लंबाई कि संभवतः स्मृति में खरी उतर सकती की --- की इजाजत दी तार हो)। वास्तव में, कि है की तरह क्या डी करता है, सरणियाँ हैं struct { size_t length; T* ptr; }, और तार बस के सरणियाँ हैं immutable(char)
टिम Timस

@ तिमस: जब तक तार को शब्द-संरेखित करने की आवश्यकता नहीं होती, तब तक कई प्लेटफ़ॉर्म पर शॉर्ट स्ट्रिंग्स के साथ काम करने की लागत लंबाई को पैक और अनपैक करने की आवश्यकता पर हावी हो जाएगी; मैं वास्तव में व्यावहारिक होने के नाते नहीं देखता। यदि कोई स्ट्रिंग्स को कंटेंट-अज्ञेयवादी आकार के बाइट एरेज़ के रूप में चाहता है, तो मुझे लगता है कि पॉइंटर से कैरेक्टर डेटा की लंबाई को अलग रखना बेहतर होगा, और एक लैंग्वेज में सूचनाओं के दोनों टुकड़ों को शाब्दिक स्ट्रिंग्स के लिए प्राप्त करने की अनुमति होगी। ।
सुपरकैट

2

सी स्टेम के आसपास के कई डिजाइन निर्णय इस तथ्य से कि जब इसे मूल रूप से लागू किया गया था, तो पैरामीटर पासिंग कुछ महंगा था। जैसे के बीच एक विकल्प दिया

void add_element_to_next(arr, offset)
  char[] arr;
  int offset;
{
  arr[offset] += arr[offset+1];
}

char array[40];

void test()
{
  for (i=0; i<39; i++)
    add_element_to_next(array, i);
}

बनाम

void add_element_to_next(ptr)
  char *p;
{
  p[0]+=p[1];
}

char array[40];

void test()
{
  int i;
  for (i=0; i<39; i++)
    add_element_to_next(arr+i);
}

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

हालांकि ऐसे कई वाजिब तरीके हैं जिनमें C में स्ट्रिंग की लंबाई एन्कोडेड हो सकती है, उस समय तक जिन तरीकों का आविष्कार किया गया था, उनमें सभी आवश्यक कार्य होंगे जो स्ट्रिंग के आधार पते को स्वीकार करने के लिए स्ट्रिंग के भाग के साथ काम करने में सक्षम होना चाहिए और दो अलग मापदंडों के रूप में वांछित सूचकांक। शून्य-बाइट समाप्ति का उपयोग करना उस आवश्यकता से बचने के लिए संभव बनाता है। यद्यपि आज की मशीनों के साथ अन्य दृष्टिकोण बेहतर होंगे (आधुनिक कंपाइलर अक्सर रजिस्टरों में पैरामीटर पास करते हैं, और मेम्स्की को स्ट्रैपी () - समतुल्य तरीकों से अनुकूलित किया जा सकता है) पर्याप्त उत्पादन कोड शून्य-बाइट टर्मिनेटेड स्ट्रिंग्स का उपयोग करता है जो कि कुछ और के लिए बदलना मुश्किल है।

पुनश्च - कुछ ऑपरेशनों पर थोड़ी गति दंड के बदले में, और लंबे समय तक तार पर अतिरिक्त ओवरहेड का एक छोटा सा हिस्सा, संभव है कि ऐसे तरीके हों जो स्ट्रिंग के साथ काम करते हैं सीधे स्ट्रिंग्स को संकेत स्वीकार करते हैं, सीमा-जाँच स्ट्रिंग बफ़र, या डेटा स्ट्रक्चर्स की पहचान दूसरे स्ट्रिंग के सबस्ट्रिंग। "स्ट्रैट" जैसे एक समारोह में कुछ ऐसा दिखता होगा जैसे [आधुनिक वाक्य रचना]

void strcat(unsigned char *dest, unsigned char *src)
{
  struct STRING_INFO d,s;
  str_size_t copy_length;

  get_string_info(&d, dest);
  get_string_info(&s, src);
  if (d.si_buff_size > d.si_length) // Destination is resizable buffer
  {
    copy_length = d.si_buff_size - d.si_length;
    if (s.src_length < copy_length)
      copy_length = s.src_length;
    memcpy(d.buff + d.si_length, s.buff, copy_length);
    d.si_length += copy_length;
    update_string_length(&d);
  }
}

K & R strcat विधि से थोड़ा बड़ा है, लेकिन यह सीमा-जाँच का समर्थन करेगा, जो K & R विधि नहीं करता है। इसके अलावा, मौजूदा विधि के विपरीत, यह आसानी से एक मनमाने ढंग से प्रतिस्थापन को समेटना संभव होगा, उदा

/* Concatenate 10th through 24th characters from src to dest */

void catpart(unsigned char *dest, unsigned char *src)
{
  struct SUBSTRING_INFO *inf;
  src = temp_substring(&inf, src, 10, 24);
  strcat(dest, src);
}

ध्यान दें कि स्ट्रिंग temp_substring द्वारा वापस की जीवन भर की उन के द्वारा सीमित किया जाएगा sऔर srcहै, जो कभी कम था (जिसके कारण विधि की आवश्यकता है infमें पारित होने के लिए - अगर यह स्थानीय था, यह मर जाएगा जब विधि लौटे)।

स्मृति लागत के संदर्भ में, 64 बाइट तक के तार और बफ़र में ओवरहेड का एक बाइट (शून्य-शून्य स्ट्रिंग्स के समान) होगा; लंबे समय तक तार थोड़े अधिक होते (चाहे एक बाइट में दो बाइट्स के बीच ओवरहेड की अनुमति हो और अधिकतम आवश्यक समय / स्पेस ट्रेडऑफ़ हो)। लंबाई / मोड बाइट के एक विशेष मूल्य का उपयोग यह इंगित करने के लिए किया जाएगा कि एक स्ट्रिंग फ़ंक्शन को एक ध्वज बाइट, एक पॉइंटर, और एक बफर लंबाई (जो तब मनमाने ढंग से किसी अन्य स्ट्रिंग में अनुक्रमित कर सकती है) युक्त संरचना दी गई थी।

बेशक, K & R ने ऐसी किसी भी चीज़ को लागू नहीं किया है, लेकिन इसकी सबसे अधिक संभावना है क्योंकि वे स्ट्रिंग हैंडलिंग पर बहुत प्रयास नहीं करना चाहते थे - एक ऐसा क्षेत्र जहां आज भी कई भाषाएं एनीमिक लगती हैं।


ऐसा कुछ भी नहीं है जो char* arrफॉर्म की संरचना struct { int length; char characters[ANYSIZE_ARRAY] };या समान रूप से इंगित करने से रोकता हो जो अभी भी एकल पैरामीटर के रूप में निष्क्रिय हो।
बिली ओनेल

@ बिलियन: उस दृष्टिकोण के साथ दो समस्याएं: (1) यह केवल स्ट्रिंग को समग्र रूप से पारित करने की अनुमति देगा, जबकि वर्तमान दृष्टिकोण भी एक स्ट्रिंग की पूंछ को पारित करने की अनुमति देता है; (2) यह छोटे तारों के साथ उपयोग किए जाने पर महत्वपूर्ण स्थान को बर्बाद कर देगा। यदि K & R स्ट्रिंग्स पर कुछ समय बिताना चाहते थे, तो वे चीजों को और अधिक मजबूत बना सकते थे, लेकिन मुझे नहीं लगता कि उनका इरादा था कि उनकी नई भाषा दस साल बाद, बहुत कम चालीस उपयोग में आएगी।
सुपरकैट

1
कॉलिंग कन्वेंशन के बारे में यह एक वास्तविकता के साथ कोई संबंध नहीं के साथ सिर्फ एक कहानी है ... यह डिजाइन में एक विचार नहीं था। और रजिस्टर-आधारित कॉलिंग कन्वेंशन "आविष्कार" पहले ही हो चुके थे। इसके अलावा, दो बिंदुओं जैसे दृष्टिकोण एक विकल्प नहीं थे क्योंकि संरचनाएं प्रथम श्रेणी में नहीं थीं ... केवल आदिम असाइन या असाइन करने योग्य थे; UNIX V7 तक स्ट्रक्चर कॉपीिंग नहीं आई। केवल एक स्ट्रिंग पॉइंटर को कॉपी करने के लिए मेम्कपी (जो भी मौजूद नहीं था) की आवश्यकता एक मजाक है। यदि आप भाषा डिजाइन का ढोंग कर रहे हैं, तो केवल अलग-थलग कार्यों के लिए, एक पूर्ण कार्यक्रम लिखने का प्रयास करें।
जिम बाल्टर

1
"यह सबसे अधिक संभावना है क्योंकि वे स्ट्रिंग हैंडलिंग पर बहुत प्रयास नहीं करना चाहते थे" - बकवास; प्रारंभिक UNIX का संपूर्ण अनुप्रयोग डोमेन स्ट्रिंग हैंडलिंग था। अगर यह उस के लिए नहीं था, तो हमने इसके बारे में कभी नहीं सुना होगा।
जिम बेल्टर

1
'मुझे नहीं लगता कि "चार्जर बफ़र की शुरुआत एक ऐसे अंतर से होती है" जो किसी भी तरह से अधिक जादुई हो "- ऐसा लगता है कि आप str[n]सही चार का संदर्भ देने जा रहे हैं । ये उन चीजों के प्रकार हैं जिनके बारे में चर्चा करने वाले लोग इसके बारे में नहीं सोचते हैं।
जिम बेल्टर

2

इस ब्लॉग पोस्ट में जोएल स्पोल्स्की के अनुसार ,

ऐसा इसलिए है क्योंकि PDP-7 माइक्रोप्रोसेसर, जिस पर UNIX और C प्रोग्रामिंग भाषा का आविष्कार किया गया था, में ASCC स्ट्रिंग प्रकार था। ASCIZ का मतलब होता है "ASCII with the Z (शून्य) अंत में।"

यहां अन्य सभी उत्तरों को देखने के बाद, मुझे विश्वास है कि भले ही यह सच है, यह सी के लिए केवल अशक्त "तार" होने का कारण है। यह पोस्ट काफी रोशन है क्योंकि स्ट्रिंग्स जैसी सरल चीजें वास्तव में काफी कठिन हो सकती हैं।


2
देखो, मैं बहुत सी बातों के लिए जोएल का सम्मान करता हूं; लेकिन यह कुछ ऐसा है जहां वह अनुमान लगा रहा है। हंस पैसेंट का जवाब सीधे सी के आविष्कारकों से आता है।
बिली ओनली

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

AFAIK .ASCIZबाइट्स के अनुक्रम के निर्माण के लिए सिर्फ एक असेंबलर स्टेटमेंट था, उसके बाद 0। इसका मतलब सिर्फ यह है कि शून्य समाप्त स्ट्रिंग उस समय एक अच्छी तरह से स्थापित अवधारणा थी। इसका मतलब यह नहीं है कि शून्य समाप्त तार एक पीडीपी- * की वास्तुकला से संबंधित कुछ थे, सिवाय इसके कि आप तंग लूप लिख सकते हैं जिसमें MOVB(एक बाइट कॉपी करें) और BNE(शाखा अगर पिछले बाइट कॉपी की गई थी शून्य नहीं थी)।
एड्रियन डब्ल्यू

यह दर्शाता है कि सी पुरानी है, भड़कीली है, पुरानी भाषा है।
शुद्ध

2

जरूरी नहीं कि राशनलेकिन लंबाई-एन्कोडेड का प्रतिरूप हो

  1. गतिशील लंबाई एन्कोडिंग के कुछ रूप स्थिर लंबाई एन्कोडिंग से बेहतर हैं जहाँ तक मेमोरी का संबंध है, यह सभी उपयोग पर निर्भर करता है। प्रमाण के लिए यूटीएफ -8 को ही देखें। यह अनिवार्य रूप से एक एकल चरित्र एन्कोडिंग के लिए एक एक्स्टेंसिबल चरित्र सरणी है। यह प्रत्येक विस्तारित बाइट के लिए एकल बिट का उपयोग करता है। एनयूएल समाप्ति 8 बिट्स का उपयोग करता है। लंबाई-उपसर्ग मुझे लगता है कि 64 बिट का उपयोग करके यथोचित रूप से अनंत लंबाई कहा जा सकता है। कितनी बार आप अपने अतिरिक्त बिट्स के मामले को हिट करते हैं, निर्णायक कारक है। केवल 1 बहुत बड़ी स्ट्रिंग? यदि आप 8 या 64 बिट्स का उपयोग कर रहे हैं, तो कौन परवाह करता है? कई छोटे तार (अंग्रेजी शब्दों के I स्ट्रिंग्स)? फिर आपकी उपसर्ग लागत एक बड़ा प्रतिशत है।

  2. समय की बचत की अनुमति देने वाली लंबाई-उपसर्गों एक वास्तविक चीज नहीं है । आपके प्रदत्त डेटा की लंबाई प्रदान करने की आवश्यकता है या नहीं, आप संकलन समय पर गिन रहे हैं, या आपको वास्तव में गतिशील डेटा प्रदान किया जा रहा है जिसे आपको एक स्ट्रिंग के रूप में एन्कोड करना होगा। एल्गोरिथ्म में कुछ बिंदुओं पर इन आकारों की गणना की जाती है। एक शून्य समाप्त स्ट्रिंग के आकार को संग्रहीत करने के लिए एक अलग चर प्रदान किया जा सकता है। जो समय-बचत मूट पर तुलना करता है। बस अंत में एक अतिरिक्त एनयूएल है ... लेकिन अगर लंबाई एनकोड उस एनयूएल को शामिल नहीं करता है तो दोनों के बीच कोई अंतर नहीं है। कोई भी एल्गोरिथम परिवर्तन आवश्यक नहीं है। बस प्री-पास करने के लिए आपको अपने लिए एक कंपाइलर / रनटाइम करने के बजाय खुद को डिजाइन करना होगा। C ज्यादातर चीजों को मैन्युअल रूप से करने के बारे में है।

  3. लंबाई-उपसर्ग वैकल्पिक होना एक विक्रय बिंदु है। मुझे हमेशा एक एल्गोरिथ्म के लिए अतिरिक्त जानकारी की आवश्यकता नहीं होती है, इसलिए इसे प्रत्येक स्ट्रिंग के लिए करने की आवश्यकता होती है, जो मेरे पूर्ववर्ती + गणना समय को ओ (एन) से नीचे छोड़ने में सक्षम नहीं बनाता है। (यानी हार्डवेयर यादृच्छिक संख्या जनरेटर 1-128। मैं "अनंत स्ट्रिंग" से खींच सकता हूं। मान लीजिए कि यह केवल इतनी तेज़ी से वर्ण उत्पन्न करता है। इसलिए हमारी स्ट्रिंग की लंबाई हर समय बदलती रहती है। लेकिन डेटा का मेरा उपयोग संभवतः कैसे परवाह नहीं करता है। मेरे पास कई यादृच्छिक बाइट्स हैं। यह बस अगले उपलब्ध अप्रयुक्त बाइट चाहता है जैसे ही यह एक अनुरोध के बाद इसे प्राप्त कर सकता है। मुझे डिवाइस पर इंतजार किया जा सकता है। लेकिन मेरे पास पहले से पढ़े गए पात्रों का एक बफर भी हो सकता है। एक लंबाई की तुलना है। अभिकलन की बेकार की बर्बादी। एक अशक्त जांच अधिक कुशल है।)

  4. लंबाई-उपसर्ग बफर अतिप्रवाह के खिलाफ एक अच्छा गार्ड है? तो पुस्तकालय कार्यों और कार्यान्वयन का समझदार उपयोग है। यदि मैं विकृत डेटा में पास करूँ तो क्या होगा? मेरा बफ़र 2 बाइट्स लंबा है, लेकिन मैं फ़ंक्शन को यह 7 बताता हूं! Ex: यदि हो जाता है () ज्ञात डेटा पर उपयोग करने का इरादा था, तो इसका आंतरिक बफर जांच हो सकता था जो संकलित बफ़र्स और मलोक () का परीक्षण करता थाकॉल और अभी भी कल्पना का पालन करें। यदि यह अज्ञात बफर में आने के लिए अज्ञात STDIN के लिए एक पाइप के रूप में इस्तेमाल किया जा रहा था, तो स्पष्ट रूप से कोई भी बफर आकार को निरस्त नहीं कर सकता है जिसका अर्थ है कि एक लंबाई arg व्यर्थ है, आपको यहां कुछ और चाहिए जैसे कि कैनरी चेक। उस बात के लिए, आप कुछ धाराओं और इनपुटों को लंबाई-उपसर्ग नहीं कर सकते, आप बस नहीं कर सकते। जिसका अर्थ है कि लंबाई की जांच को एल्गोरिथ्म में बनाया जाना चाहिए, न कि टाइपिंग सिस्टम का एक जादुई हिस्सा। टीएल; डीआर नूल-टर्मिनेटेड को कभी असुरक्षित नहीं होना पड़ा, यह दुरुपयोग के माध्यम से बस उसी तरह समाप्त हो गया।

  5. काउंटर-काउंटर बिंदु: एनयूएल-समाप्ति द्विआधारी पर कष्टप्रद है। आपको या तो यहां लंबाई-उपसर्ग करने की आवश्यकता है या एनयूएल बाइट्स को किसी तरह से बदलना है: एस्केप-कोड, रेंज रीमैपिंग, आदि ... जो निश्चित रूप से अधिक स्मृति-उपयोग / कम-जानकारी / अधिक-संचालन-प्रति-बाइट का अर्थ है। लंबाई-उपसर्ग ज्यादातर यहां युद्ध जीतता है। एक परिवर्तन के लिए केवल इतना ही है कि लंबाई-उपसर्ग के तारों को कवर करने के लिए कोई अतिरिक्त कार्य नहीं लिखा जाना चाहिए। जिसका अर्थ है कि आपके अधिक अनुकूलित उप-ओ (एन) रूटीन पर आप उन्हें अधिक कोड जोड़े बिना अपने ओ (एन) समकक्षों के रूप में स्वचालित रूप से कार्य कर सकते हैं। एनयूएल भारी तारों पर इस्तेमाल किए जाने पर, निश्चित रूप से, समय / मेमोरी / संपीड़न अपशिष्ट नीचे है।बाइनरी डेटा पर काम करने के लिए आप अपने पुस्तकालय को कितना दोहराते हैं, इस पर निर्भर करते हुए, यह पूरी तरह से लंबाई-पूर्व-भाग के साथ काम करने के लिए समझ में आता है। उन्होंने कहा कि कोई भी लंबाई-उपसर्ग स्ट्रिंग्स के साथ भी ऐसा कर सकता है ... -1 लंबाई का मतलब एनयूएल-टर्मिनेटेड हो सकता है और आप लंबाई-टर्मिनेटेड एनयूएल-टर्मिनेटेड स्ट्रिंग्स का उपयोग कर सकते हैं।

  6. कॉनैट: "ओ (एन + एम) बनाम ओ (एम)" मैं आपका उल्लेख मान रहा हूं कि समवर्ती करने के बाद स्ट्रिंग की कुल लंबाई के रूप में मी। क्योंकि उन दोनों को ऑपरेशन की संख्या कम से कम करनी होगी (आप सिर्फ सौदा नहीं कर सकते -से स्ट्रिंग 1, क्या होगा अगर आपको रियललोक करना है?)। और मैं मान रहा हूँ कि n संचालन की एक मिथकीय मात्रा है जो अब आपको पूर्व-गणना के कारण नहीं करनी है। यदि ऐसा है, तो उत्तर सरल है: पूर्व-गणना। अगरआप हमेशा जोर देकर कहते हैं कि आपको वास्तविक मेमोरी की आवश्यकता नहीं होगी और यह बड़े-ओ संकेतन का आधार है तो इसका उत्तर और भी सरल है: स्ट्रिंग 1 के अंत के लिए आवंटित मेमोरी पर द्विआधारी खोज करें, स्पष्ट रूप से एक बड़ा है हमारे लिए वास्तविक 1 के बाद चिंता न करने के लिए स्ट्रिंग 1 के बाद अनंत शून्य का स्वैच। वहाँ, आसानी से लॉग इन करने के लिए n (n) मिला और मैंने मुश्किल से कोशिश की। यदि आप लॉग (n) को याद करते हैं तो अनिवार्य रूप से केवल वास्तविक कंप्यूटर पर 64 जितना बड़ा है, जो कि अनिवार्य रूप से O (64 + m) है, जो अनिवार्य रूप से O (m) है। (और हाँ आज तर्क का उपयोग वास्तविक डेटा संरचनाओं के रन-टाइम विश्लेषण में किया गया है। यह मेरे सिर के ऊपर से बकवास नहीं है।)

  7. कॉनकैट () / लेन () फिर से : परिणाम याद करें। आसान। यदि संभव हो तो / पूर्व-गणना में सभी गणनाओं को बदल देता है। यह एक एल्गोरिथम निर्णय है। यह भाषा का एक लागू बाधा नहीं है।

  8. एनयूएल समाप्ति के साथ स्ट्रिंग प्रत्यय गुजरना आसान / संभव है। यह निर्भर करता है कि लंबाई-उपसर्ग कैसे लागू किया जाता है यह मूल स्ट्रिंग पर विनाशकारी हो सकता है और कभी-कभी संभव भी नहीं हो सकता है। प्रतिलिपि की आवश्यकता है और O (1) के बजाय O (n) पास करें।

  9. एनयूएल-टर्मिनेटेड बनाम लंबाई-उपसर्ग के लिए तर्क-पासिंग / डी-रेफरेंसिंग कम है। जाहिर है क्योंकि आप कम जानकारी दे रहे हैं। यदि आपको लंबाई की आवश्यकता नहीं है, तो यह बहुत पदचिह्न बचाता है और अनुकूलन की अनुमति देता है।

  10. आप धोखा दे सकते हैं। यह वास्तव में सिर्फ एक संकेतक है। कौन कहता है कि आपको इसे एक स्ट्रिंग के रूप में पढ़ना होगा? क्या होगा यदि आप इसे एकल चरित्र या फ्लोट के रूप में पढ़ना चाहते हैं? क्या होगा यदि आप विपरीत करना चाहते हैं और एक स्ट्रिंग के रूप में फ्लोट पढ़ते हैं? यदि आप सावधान हैं तो आप एनयूएल-समाप्ति के साथ ऐसा कर सकते हैं। आप लंबाई-उपसर्ग के साथ ऐसा नहीं कर सकते, यह आमतौर पर एक पॉइंटर से अलग एक डेटा प्रकार है। आप सबसे अधिक संभावना है कि एक बाइट को बाय-बाय करें और लंबाई प्राप्त करें। बेशक, यदि आप एक संपूर्ण फ्लोट की तरह कुछ चाहते थे (शायद इसके अंदर एक एनयूएल है) तो आपको वैसे भी बाइट-बाय-बाय पढ़ना होगा, लेकिन विवरण आपको तय करना बाकी है।

TL, DR क्या आप बाइनरी डेटा का उपयोग कर रहे हैं? यदि नहीं, तो एनयूएल-समाप्ति अधिक एल्गोरिथम स्वतंत्रता की अनुमति देता है। यदि हाँ, तो कोड मात्रा बनाम गति / स्मृति / संपीड़न आपकी मुख्य चिंता है। दो दृष्टिकोणों या संस्मरण का मिश्रण सबसे अच्छा हो सकता है।


9 थोड़े ऑफ-बेस / गलत-प्रतिनिधित्व किया गया था। लंबाई पूर्व-निर्धारण में यह समस्या नहीं है। एक अलग चर के रूप में दसवीं पास करना । हम प्री-फ़िक्स के बारे में बात कर रहे थे लेकिन मैं भाग गया। फिर भी एक अच्छी बात सोचने के लिए मैं इसे वहीं छोड़ दूंगा। : d
ब्लैक

1

मैं "सी कोई स्ट्रिंग नहीं है" जवाब नहीं खरीदते हैं। सच है, सी बिल्ट-इन उच्च-स्तरीय प्रकारों का समर्थन नहीं करता है, लेकिन आप अभी भी सी में डेटा-संरचनाओं का प्रतिनिधित्व कर सकते हैं और यही एक स्ट्रिंग है। तथ्य यह है कि एक स्ट्रिंग सी में एक सूचक है इसका मतलब यह नहीं है कि पहली एन बाइट्स लंबाई के रूप में विशेष अर्थ पर नहीं ले सकती।

विंडोज / COM डेवलपर्स उस BSTRप्रकार से बहुत परिचित होंगे जो वास्तव में इस प्रकार है - एक लंबाई-पूर्व उपसर्ग C स्ट्रिंग जहां वास्तविक चरित्र डेटा बाइट 0 पर शुरू नहीं होता है।

तो ऐसा लगता है कि शून्य-समाप्ति का उपयोग करने का निर्णय केवल लोगों की पसंद है, भाषा की आवश्यकता नहीं है।


-3

नीचे दिए गए कोड स्वीकार करें:

char s [4] = "abcd";

और यह ठीक है अगर हम इलाज करते हैं तो यह एक वर्ण के रूप में है लेकिन स्ट्रिंग नहीं। यही है, हम इसे s [0], s [1], s [2], और s [3], या यहां तक ​​कि मेमसीपी (भाग्य, s, 4) के साथ एक्सेस कर सकते हैं। जब हम पुट (एस) के साथ प्रयास कर रहे हैं, या गंदे अक्षर प्राप्त करेंगे, या स्ट्रैपी (डेस्ट, एस) के साथ खराब होंगे।


@ एड्रियन डब्ल्यू। यह मान्य सी है। सटीक लंबाई के तार विशेष आवरण हैं और एनयूएल उनके लिए छोड़ा गया है। यह आम तौर पर एक नासमझ अभ्यास है, लेकिन फोरकाक "स्ट्रिंग्स" का उपयोग करने वाले हेडर संरचनाओं को आबाद करने जैसे मामलों में उपयोगी हो सकता है।
केविन थिबेडो

तुम सही हो। यह मान्य सी है, जैसा कि वर्णित किया गया है, संकलन और व्यवहार करेगा। पतन का कारण (मेरा नहीं ...) शायद यह है कि यह जवाब किसी भी तरह से ओपी के सवाल का जवाब नहीं देता है।
एड्रियन डब्ल्यू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.