C ++ में स्ट्रिंग और चार [] प्रकारों के बीच अंतर


126

मैं थोड़ा सी जानता हूं और अब मैं सी ++ पर एक नजर डाल रहा हूं। मुझे C स्ट्रिंग से निपटने के लिए सरणियों का उपयोग करने के लिए उपयोग किया जाता है, लेकिन जब मैं C ++ कोड को देखता हूं तो मैं देखता हूं कि दोनों स्ट्रिंग प्रकार और चार सरणियों का उपयोग करने वाले उदाहरण हैं:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string mystr;
  cout << "What's your name? ";
  getline (cin, mystr);
  cout << "Hello " << mystr << ".\n";
  cout << "What is your favorite team? ";
  getline (cin, mystr);
  cout << "I like " << mystr << " too!\n";
  return 0;
}

तथा

#include <iostream>
using namespace std;

int main () {
  char name[256], title[256];

  cout << "Enter your name: ";
  cin.getline (name,256);

  cout << "Enter your favourite movie: ";
  cin.getline (title,256);

  cout << name << "'s favourite movie is " << title;

  return 0;
}

( http://www.cplusplus.com से दोनों उदाहरण )

मुझे लगता है कि यह एक व्यापक रूप से पूछा और उत्तर दिया गया है (स्पष्ट?) सवाल है, लेकिन यह अच्छा होगा अगर कोई मुझे बता सकता है कि सी ++ में तार से निपटने के लिए उस दो तरीकों के बीच क्या अंतर है (प्रदर्शन, एपीआई एकीकरण, जिस तरह से हर एक है बेहतर, ...)।

धन्यवाद।


इससे मदद मिल सकती है: C ++ char * vs std :: string
Wael Dalloul

जवाबों:


187

एक वर्ण सरणी सिर्फ यह है कि - वर्णों की एक सरणी:

  • यदि स्टैक पर आवंटित किया जाता है (जैसे आपके उदाहरण में), तो यह हमेशा उदा रहेगा। 256 बाइट्स में कोई फर्क नहीं पड़ता कि इसमें कितना समय है
  • यदि आपको ढेर पर आबंटित किया जाता है (मैलोक () या नए चार [] का उपयोग करके) तो आप मेमोरी को बाद में जारी करने के लिए जिम्मेदार हैं और आपके पास हमेशा ढेर आवंटन का ओवरहेड होगा।
  • यदि आप सरणी में 256 से अधिक वर्णों के पाठ को कॉपी करते हैं, तो यह क्रैश हो सकता है, बदसूरत मुखर संदेश उत्पन्न कर सकता है या आपके कार्यक्रम में कहीं और अस्पष्ट (गलत) व्यवहार का कारण बन सकता है।
  • पाठ की लंबाई निर्धारित करने के लिए, सरणी को वर्ण, वर्ण द्वारा वर्ण, \ 0 वर्ण के लिए स्कैन करना होगा।

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

आप इस तरह से एक स्ट्रिंग चार्ट का उपयोग कर सकते हैं:

std::string myString = "Hello World";
const char *myStringChars = myString.c_str();

C ++ स्ट्रिंग्स में एम्बेडेड \ 0 वर्ण हो सकते हैं, गिनती के बिना उनकी लंबाई जान सकते हैं, छोटे ग्रंथों के लिए ढेर-आवंटित चार सरणियों से तेज़ हैं और आपको बफर ओवररन से बचा सकते हैं। साथ ही वे अधिक पठनीय और उपयोग में आसान होते हैं।


हालाँकि, C ++ स्ट्रिंग्स DLL सीमाओं के पार उपयोग के लिए उपयुक्त (बहुत) उपयुक्त नहीं हैं, क्योंकि इसके लिए ऐसे DLL फ़ंक्शन के किसी भी उपयोगकर्ता की आवश्यकता होगी, यह सुनिश्चित करने के लिए कि वह सटीक समान कंपाइलर और C ++ रनटाइम कार्यान्वयन का उपयोग कर रहा है, ऐसा न हो कि वह अपनी स्ट्रिंग क्लास को अलग तरह से जोखिम में डाल दे।

आम तौर पर, एक स्ट्रिंग वर्ग भी कॉलिंग हीप पर अपनी हीप मेमोरी को जारी करेगा, इसलिए यह केवल तभी मेमोरी को फ्रीज कर सकेगा जब आप रनटाइम के साझा (.dll या .so) संस्करण का उपयोग कर रहे हों।

संक्षेप में: अपने सभी आंतरिक कार्यों और विधियों में C ++ स्ट्रिंग्स का उपयोग करें। यदि आप कभी भी .dll या .so लिखते हैं, तो C स्ट्रिंग्स का उपयोग अपने सार्वजनिक (dll / तथाकथित) कार्यों में करें।


4
इसके अलावा, तार में सहायक कार्यों का एक गुच्छा होता है जो वास्तव में साफ-सुथरा हो सकता है।
हाकॉन

1
मैं DLL सीमाओं के बारे में थोड़ा विश्वास नहीं करता। बहुत ही विशेष curcumstances के तहत यह संभावित रूप से टूट सकता है ((एक DLL स्टेटिक रूप से दूसरे DLL द्वारा उपयोग किए गए रनटाइम के एक अलग संस्करण के खिलाफ है) और इससे भी बदतर चीजें शायद इन स्थितियों में पहली बार होंगी) लेकिन सामान्य स्थिति में जहां हर कोई डिफ़ॉल्ट का उपयोग कर रहा है मानक रनटाइम का साझा संस्करण (डिफ़ॉल्ट) ऐसा नहीं होगा।
मार्टिन यॉर्क

2
उदाहरण: आप एक सार्वजनिक पुस्तकालय के VC2008SP1- संकलित बायनेरिज़ को वितरित करते हैं, जिसे libfoo कहा जाता है, जिसका std :: string & इसके सार्वजनिक API में है। अब कोई आपके libfoo.dll को डाउनलोड करता है और एक डीबग बिल्ड करता है। उनका std :: string बहुत अच्छी तरह से इसमें कुछ अतिरिक्त डिबग फ़ील्ड्स हो सकता है, जिससे डायनेमिक स्ट्रिंग्स के लिए पॉइंटर को ऑफ़सेट किया जा सकता है।
साइगॉन

2
उदाहरण 2: 2010 में, कोई व्यक्ति आपके libfoo.dll को डाउनलोड करता है और अपने VC2010- निर्मित एप्लिकेशन में इसका उपयोग करता है। उसका कोड लोड करता है MSVCP100.dll और आपका libfoo.dll अभी भी MSVCP90.dll को लोड करता है -> आपको दो ढेर मिलते हैं -> मेमोरी को मुक्त नहीं किया जा सकता है, यदि डिबग्यू स्ट्रिंग मोड को संशोधित करता है और हाथों को एक std :: string के साथ संशोधित करता है सूचक वापस।
साइगॉन

1
मैं बस "संक्षेप में: अपने सभी आंतरिक कार्यों और विधियों में C ++ स्ट्रिंग्स का उपयोग करने जा रहा हूं।" आपके उदाहरणों को समझने की कोशिश करने से मेरे दिमाग की शक्ति चली गई।
स्टीफन

12

Arkaitz सही है stringजो एक प्रबंधित प्रकार है। आपके लिए इसका मतलब यह है कि आपको इस बात की चिंता करने की आवश्यकता नहीं है कि स्ट्रिंग कितनी लंबी है, और न ही आपको स्ट्रिंग की मेमोरी को मुक्त या वास्तविक बनाने के बारे में चिंता करना है।

दूसरी ओर, char[]ऊपर के मामले में संकेतन ने वर्ण बफर को ठीक 256 वर्णों तक सीमित कर दिया है। यदि आपने 256 से अधिक वर्णों को उस बफ़र में लिखने की कोशिश की है, तो सबसे अच्छी तरह से आप अन्य मेमोरी को अधिलेखित कर देंगे जो आपका प्रोग्राम "मालिक" है। सबसे कम, आप स्मृति को अधिलेखित करने का प्रयास करेंगे जो आपके पास नहीं है, और आपका ओएस मौके पर आपके कार्यक्रम को मार देगा।

जमीनी स्तर? स्ट्रिंग बहुत अधिक प्रोग्रामर फ्रेंडली हैं, char [] s कंप्यूटर के लिए बहुत अधिक कुशल हैं।


4
सबसे खराब रूप से, अन्य लोग स्मृति को अधिलेखित कर देंगे और आपके कंप्यूटर पर दुर्भावनापूर्ण कोड चलाएंगे। बफ़र ओवरफ़्लो भी देखें ।
डेविड जॉनस्टोन

6

खैर, स्ट्रिंग प्रकार चरित्र तार के लिए एक पूरी तरह से प्रबंधित वर्ग है, जबकि चार [] अभी भी वही है जो सी में था, एक बाइट सरणी आपके लिए एक चरित्र स्ट्रिंग का प्रतिनिधित्व करता है।

एपीआई और मानक पुस्तकालय के संदर्भ में सब कुछ स्ट्रिंग्स के संदर्भ में लागू किया जाता है और चार [नहीं], लेकिन अभी भी बहुत सारे फ़ंक्शंस हैं जो कि लीब को प्राप्त होते हैं [इसलिए] आपको इसका उपयोग करने की आवश्यकता हो सकती है, इसके अलावा मैं इसके अलावा हमेशा std :: string का उपयोग करें।

बेशक दक्षता की दृष्टि से अप्रबंधित मेमोरी का एक कच्चा बफर लगभग हमेशा बहुत सारी चीजों के लिए तेज होगा, लेकिन उदाहरण के लिए स्ट्रिंग्स की तुलना करते हुए ध्यान रखें, std :: string में हमेशा यह जांचने के लिए आकार होता है, जबकि char [] आप के साथ चरित्र द्वारा चरित्र की तुलना करने की आवश्यकता है।


5

मैं व्यक्तिगत रूप से ऐसा कोई कारण नहीं देखता कि पुराने कोड के साथ संगतता को छोड़कर कोई चार * या चार [] का उपयोग करना चाहे। std :: c- स्ट्रिंग का उपयोग करने से स्ट्रिंग का कोई धीमा नहीं है, सिवाय इसके कि यह आपके लिए फिर से आवंटन को संभाल लेगा। इसे बनाते समय आप इसका आकार निर्धारित कर सकते हैं, और इस प्रकार यदि आप चाहें तो पुन: आवंटन से बच सकते हैं। यह अनुक्रमणिका ऑपरेटर ([]) निरंतर समय तक पहुँच प्रदान करता है (और शब्द के प्रत्येक अर्थ में सी-स्ट्रिंग इंडेक्सर का उपयोग करने के समान शब्द है)। इस विधि का उपयोग करने से आपको सुरक्षा की जाँच के साथ-साथ सी-स्ट्रिंग्स के साथ कुछ भी नहीं मिलता है, जब तक कि आप इसे नहीं लिखते। आपकी संकलक सबसे अधिक बार रिलीज़ मोड में अनुक्रमणिका के उपयोग का अनुकूलन करेगी। सी-स्ट्रिंग्स के साथ गड़बड़ करना आसान है; डिलीट बनाम डिलीट [], सिक्योरिटी सेफ्टी जैसी चीजें, यहां तक ​​कि कैसे एक सी-स्ट्रिंग को पुनः प्राप्त करें।

और जब आपको एडवांस्ड कॉन्सेप्ट्स से निपटना होता है जैसे कि गाय के तार, और गैर-एमटी के लिए एमटी आदि, तो आपको std :: string की आवश्यकता होगी।

यदि आप कॉपियों के बारे में चिंतित हैं, तो जब तक आप संदर्भों का उपयोग करते हैं, और जहाँ भी आप कर सकते हैं, काँस्ट संदर्भों का उपयोग करते हैं, तो आपके पास कॉपियों के कारण कोई ओवरहेड नहीं होगा, और यह वही है जो आप सी-स्ट्रिंग के साथ करेंगे।


+1 हालांकि आपने DLL संगतता जैसे कार्यान्वयन मुद्दों पर विचार नहीं किया, यू को गाय मिली।

मुझे क्या पता है कि मेरी चार सरणी 12 बाइट्स में है? अगर मैं इसके लिए एक स्ट्रिंग तत्काल करता हूं तो यह वास्तव में कुशल नहीं हो सकता है?
डेविड David वोंग

@ डेविड: अगर आपके पास बेहद परफेक्ट संवेदनशील कोड है, तो हाँ। आप std पर विचार कर सकते हैं :: string के आरंभ के अतिरिक्त स्ट्रिंग ctor कॉल ओवरहेड के रूप में :: string सदस्य। लेकिन याद रखें समय से पहले अनुकूलन ने बहुत सारे कोड आधार अनावश्यक रूप से सी-स्टाइल किए हैं, इसलिए सावधान रहें।
अभय

1

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


0

(Char *) को string.begin () के रूप में सोचें। आवश्यक अंतर यह है कि (चार *) एक पुनरावृत्त है और एसटी :: स्ट्रिंग एक कंटेनर है। यदि आप मूल तार से चिपके रहते हैं तो a (char *) आपको क्या देगा std :: string :: iterator करता है। आप (चार *) का उपयोग कर सकते हैं जब आप एक सूचना का लाभ चाहते हैं और सी के साथ संगतता भी, लेकिन यह अपवाद नहीं है और नियम नहीं है। हमेशा की तरह, पुनरावृत्ति अमान्य से सावधान रहें। जब लोग कहते हैं (चार *) यह सुरक्षित नहीं है तो उनका मतलब क्या है। यह किसी भी अन्य C ++ पुनरावृत्त की तरह सुरक्षित है।


0

अंतर में से एक नल समाप्ति (\ 0) है।

C और C ++ में, char * या char [] एक पैरामीटर के रूप में एक सिंगल char को पॉइंटर लेगा और 0 मेमोरी वैल्यू (अक्सर शून्य टर्मिनेटर कहा जाता है) तक मेमोरी के साथ ट्रैक करेगा।

C ++ स्ट्रिंग्स में एम्बेडेड \ 0 वर्ण हो सकते हैं, बिना गिनती के उनकी लंबाई जान सकते हैं।

#include<stdio.h>
#include<string.h>
#include<iostream>

using namespace std;

void NullTerminatedString(string str){
   int NUll_term = 3;
   str[NUll_term] = '\0';       // specific character is kept as NULL in string
   cout << str << endl <<endl <<endl;
}

void NullTerminatedChar(char *str){
   int NUll_term = 3;
   str[NUll_term] = 0;     // from specific, all the character are removed 
   cout << str << endl;
}

int main(){
  string str = "Feels Happy";
  printf("string = %s\n", str.c_str());
  printf("strlen = %d\n", strlen(str.c_str()));  
  printf("size = %d\n", str.size());  
  printf("sizeof = %d\n", sizeof(str)); // sizeof std::string class  and compiler dependent
  NullTerminatedString(str);


  char str1[12] = "Feels Happy";
  printf("char[] = %s\n", str1);
  printf("strlen = %d\n", strlen(str1));
  printf("sizeof = %d\n", sizeof(str1));    // sizeof char array
  NullTerminatedChar(str1);
  return 0;
}

आउटपुट:

strlen = 11
size = 11
sizeof = 32  
Fee s Happy


strlen = 11
sizeof = 12
Fee

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