[c++] Std :: string को const char * या char * में कैसे परिवर्तित करें?



Answers

दिया गया ...

std::string x = "hello";

'स्ट्रिंग' से `char *` या `const char *` प्राप्त करना

एक वर्ण सूचक कैसे प्राप्त करें जो वैध है जबकि x गुंजाइश में रहता है और आगे संशोधित नहीं किया जाता है

सी ++ 11 चीजों को सरल बनाता है; निम्नलिखित सभी एक ही आंतरिक स्ट्रिंग बफर तक पहुंच प्रदान करते हैं:

const char* p_c_str = x.c_str();
const char* p_data  = x.data();
const char* p_x0    = &x[0];

      char* p_x0_rw = &x[0];  // compiles iff x is not const...

सभी उपरोक्त पॉइंटर्स वही मान रखेंगे - बफर में पहले वर्ण का पता। यहां तक ​​कि एक खाली स्ट्रिंग में "बफर में पहला अक्षर" होता है, क्योंकि सी ++ 11 स्पष्ट रूप से निर्दिष्ट स्ट्रिंग सामग्री के बाद हमेशा एक अतिरिक्त NUL / 0 टर्मिनेटर चरित्र रखने की गारंटी देता है (उदाहरण के लिए std::string("this\0that", 9) में एक बफर होल्डिंग होगा "this\0that\0" )।

उपर्युक्त बिंदुओं में से किसी को भी देखते हुए:

char c = p[n];   // valid for n <= x.size()
                 // i.e. you can safely read the NUL at p[x.size()]

केवल गैर- const पॉइंटर के लिए &x[0] :

p_x0_rw[n] = c;  // valid for n <= x.size() - 1
                 // i.e. don't overwrite the implementation maintained NUL

स्ट्रिंग में कहीं और एक एनयूएल लिखना string के size() को नहीं बदलता है; string को किसी भी संख्या में एनयूएल रखने की अनुमति है - उन्हें std::string (सी ++ 03 में समान) द्वारा कोई विशेष उपचार नहीं दिया जाता है।

सी ++ 03 में , चीजें काफी जटिल थीं (महत्वपूर्ण अंतर हाइलाइट किए गए ):

  • x.data()

    • स्ट्रिंग के आंतरिक बफर को रिटर्न const char* देता है जिसे मानक द्वारा एनयूएल के साथ समाप्त करने की आवश्यकता नहीं होती है (यानी हो सकता है ['h', 'e', 'l', 'l', 'o'] अनियंत्रित या कचरा मूल्य, अपरिभाषित व्यवहार के साथ आकस्मिक पहुंच के साथ)।
      • x.size() अक्षर पढ़ने के लिए सुरक्षित हैं, यानी x[0] x[x.size() - 1] माध्यम से x[x.size() - 1]
      • खाली तारों के लिए, आपको कुछ गैर-नल पॉइंटर की गारंटी है, जिस पर 0 सुरक्षित रूप से जोड़ा जा सकता है (hurray!), लेकिन आपको उस सूचक को अव्यवस्थित नहीं करना चाहिए।
  • &x[0]

    • खाली तारों के लिए इसने अपरिभाषित व्यवहार किया है (21.3.4)
      • उदाहरण दिया गया f(const char* p, size_t n) { if (n == 0) return; ...whatever... } f(const char* p, size_t n) { if (n == 0) return; ...whatever... } आपको f(&x[0], x.size()); कॉल नहीं करना चाहिए f(&x[0], x.size()); जब x.empty() - बस f(x.data(), ...)
    • अन्यथा, x.data() अनुसार, लेकिन:
      • गैर- const x यह एक गैर- const char* पॉइंटर उत्पन्न करता है; आप स्ट्रिंग सामग्री को ओवरराइट कर सकते हैं
  • x.c_str()

    • मूल्य के एएससीआईआईजेड (एनयूएल-समाप्त) प्रतिनिधित्व के लिए कॉन्स const char* देता है (यानी ['एच', 'ई', 'एल', 'एल', 'ओ', '\ 0'])।
    • हालांकि कुछ अगर किसी भी कार्यान्वयन ने ऐसा करने का विकल्प चुना है, तो सी ++ 03 मानक को स्ट्रिंग कार्यान्वयन को स्वतंत्र रूप से गैर-एनयूएल समाप्त बफर से "एक्सपोज़ड" से फ्लाई पर एक अलग एनयूएल-समाप्त बफर बनाने की स्वतंत्रता को अनुमति देने के लिए कहा गया था। x.data() और &x[0]
    • x.size() + 1 अक्षर पढ़ने के लिए सुरक्षित हैं।
    • खाली तारों के लिए भी सुरक्षित गारंटी (['\ 0'])।

बाहरी कानूनी सूचकांक तक पहुंचने के नतीजे

जिस भी तरह से आप पॉइंटर प्राप्त करते हैं, आपको ऊपर दिए गए विवरणों में मौजूद पात्रों की तुलना में सूचक से आगे स्मृति तक पहुंच नहीं करनी चाहिए। ऐसा करने के प्रयासों में अपरिभाषित व्यवहार है , आवेदन क्रैश और कचरा के परिणाम भी पढ़ने के लिए, और अतिरिक्त थोक डेटा, भ्रष्टाचार और / या लिखने के लिए सुरक्षा भेद्यता के वास्तविक परिणाम के साथ।

उन पॉइंटर्स को कब अवैध किया जाता है?

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

x पत्तियों के दायरे के बाद भी एक चरित्र सूचक को वैध कैसे प्राप्त करें या नीचे और संशोधित किया गया है यह भी देखें ....

तो, जो उपयोग करने के लिए बेहतर है?

सी ++ 11 से, ASCIIZ डेटा के लिए .c_str() उपयोग करें, और "बाइनरी" डेटा के लिए .data .data() (नीचे आगे बताया गया है)।

सी ++ 03 में, .c_str() उपयोग करें जब तक कि निश्चित नहीं है कि .c_str() पर्याप्त है, और .data() को &x[0] पसंद करते हैं क्योंकि यह खाली तारों के लिए सुरक्षित है ....

... उपयुक्त होने पर data() का उपयोग करने के लिए पर्याप्त प्रोग्राम को समझने का प्रयास करें, या आप शायद अन्य गलतियां करेंगे ...

.c_str() द्वारा .c_str() ASCII NUL '\ 0' वर्ण का उपयोग कई कार्यों द्वारा किया गया है जो एक संगत मूल्य के रूप में प्रासंगिक और सुरक्षित-पहुंच वाले डेटा के अंत को दर्शाता है। यह सी ++ दोनों पर लागू होता है - केवल fstream::fstream(const char* filename, ...) जैसे साझा किए गए कार्यों और strchr() , और printf() जैसे साझा-साथ-सी फ़ंक्शन।

दिए गए बफर के बारे में C ++ 03 की .c_str() की गारंटी दी गई है .c_str() के एक सुपर-सेट हैं, आप हमेशा सुरक्षित रूप से .c_str() उपयोग कर सकते हैं, लेकिन लोग कभी-कभी ऐसा नहीं करते क्योंकि:

  • .data() का उपयोग करके अन्य प्रोग्रामर को स्रोत कोड पढ़ने के लिए संचारित किया जाता है कि डेटा ASCIIZ नहीं है (बल्कि, आप डेटा के ब्लॉक को संग्रहीत करने के लिए स्ट्रिंग का उपयोग कर रहे हैं (जो कभी-कभी वास्तव में भी पाठक नहीं है), या आप ' इसे किसी अन्य फ़ंक्शन पर पास कर दें जो इसे "बाइनरी" डेटा के ब्लॉक के रूप में मानता है। यह सुनिश्चित करने में एक महत्वपूर्ण अंतर्दृष्टि हो सकती है कि अन्य प्रोग्रामर कोड परिवर्तन डेटा को सही तरीके से संभालते रहें।
  • सी ++ 03 केवल: एक मामूली मौका है कि आपके string कार्यान्वयन को एनयूएल समाप्त बफर तैयार करने के लिए कुछ अतिरिक्त मेमोरी आवंटन और / या डेटा कॉपी करने की आवश्यकता होगी

एक और संकेत के रूप में, यदि किसी फ़ंक्शन के पैरामीटर को ( x.size() ) char* आवश्यकता होती है लेकिन x.size() प्राप्त करने पर जोर नहीं देते हैं, तो फ़ंक्शन को शायद ASCIIZ इनपुट की आवश्यकता होती है, इसलिए .c_str() एक अच्छी पसंद है (फ़ंक्शन की ज़रूरत है यह जानने के लिए कि पाठ कहां से समाप्त होता है, इसलिए यदि यह एक अलग पैरामीटर नहीं है तो यह केवल लम्बाई उपसर्ग या सेंटीनेल या कुछ निश्चित अपेक्षित लंबाई जैसे सम्मेलन हो सकता है)।

x पत्तियों के दायरे के बाद भी एक चरित्र सूचक को वैध कैसे प्राप्त करें या आगे संशोधित किया जाए

आपको string x की सामग्री को x बाहर एक नए मेमोरी क्षेत्र में कॉपी करने की आवश्यकता होगी। यह बाहरी बफर कई स्थानों पर हो सकता है जैसे कि एक और string या कैरेक्टर एरे वैरिएबल, यह अलग-अलग दायरे में होने के कारण x से भिन्न जीवनकाल हो सकता है (उदाहरण के लिए नामस्थान, वैश्विक, स्थैतिक, ढेर, साझा स्मृति, मेमोरी मैप फ़ाइल)।

std::string x से पाठ को एक स्वतंत्र वर्ण सरणी में कॉपी करने के लिए:

// USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE
std::string old_x = x;
// - old_x will not be affected by subsequent modifications to x...
// - you can use `&old_x[0]` to get a writable char* to old_x's textual content
// - you can use resize() to reduce/expand the string
//   - resizing isn't possible from within a function passed only the char* address

std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL
// Copies ASCIIZ data but could be less efficient as it needs to scan memory to
// find the NUL terminator indicating string length before allocating that amount
// of memory to copy into, or more efficient if it ends up allocating/copying a
// lot less content.
// Example, x == "ab\0cd" -> old_x == "ab".

// USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03
std::vector<char> old_x(x.data(), x.data() + x.size());       // without the NUL
std::vector<char> old_x(x.c_str(), x.c_str() + x.size() + 1);  // with the NUL

// USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N"
// (a bit dangerous, as "known" things are sometimes wrong and often become wrong)
char y[N + 1];
strcpy(y, x.c_str());

// USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (e.g. Hello\0->Hel\0)
char y[N + 1];
strncpy(y, x.c_str(), N);  // copy at most N, zero-padding if shorter
y[N] = '\0';               // ensure NUL terminated

// USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH
char* y = alloca(x.size() + 1);
strcpy(y, x.c_str());

// USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION)
char y[x.size() + 1];
strcpy(y, x.c_str());

// USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = new char[x.size() + 1];
strcpy(y, x.c_str());
//     or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str());
// use y...
delete[] y; // make sure no break, return, throw or branching bypasses this

// USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE
// see boost shared_array usage in Johannes Schaub's answer

// USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = strdup(x.c_str());
// use y...
free(y);

एक string से उत्पन्न char* या const char* को प्राप्त करने के अन्य कारण

तो, ऊपर आपने देखा है कि कैसे ( const ) char* , और मूल string स्वतंत्र पाठ की एक प्रति कैसे बनाएं, लेकिन आप इसके साथ क्या कर सकते हैं? उदाहरणों का एक यादृच्छिक smattering ...

  • सी ++ string के पाठ में "सी" कोड पहुंच दें, जैसे printf("x is '%s'", x.c_str());
  • x के पाठ को अपने फ़ंक्शन के कॉलर द्वारा निर्दिष्ट बफर में कॉपी करें (उदाहरण के लिए strncpy(callers_buffer, callers_buffer_size, x.c_str()) ), या डिवाइस I / O के लिए उपयोग की जाने वाली अस्थिर स्मृति (उदाहरण के for (const char* p = x.c_str(); *p; ++p) *p_device = *p; )
  • पहले से ही कुछ ASCIIZ टेक्स्ट (जैसे strcat(other_buffer, x.c_str()) युक्त वर्ण वर्ण में x का टेक्स्ट संलग्न करें) - बफर को strcat(other_buffer, x.c_str()) न करने के लिए सावधान रहें (कई स्थितियों में आपको strncat का उपयोग करने की आवश्यकता हो सकती है)
  • किसी फ़ंक्शन से एक const char* या char* लौटाएं (शायद ऐतिहासिक कारणों से - क्लाइंट आपके मौजूदा एपीआई का उपयोग कर रहा है - या सी संगतता के लिए आप std::string को वापस नहीं करना चाहते हैं, लेकिन अपनी string के डेटा को प्रतिलिपि बनाना चाहते हैं कहीं कॉलर के लिए)
    • सावधान रहें कि एक स्थानीय string वैरिएबल के बाद कॉलर द्वारा अस्वीकृत किए जाने वाले पॉइंटर को वापस न करें, जिस पर पॉइंटर पॉइंट ने गुंजाइश छोड़ी है
    • अलग-अलग std::string कार्यान्वयन (जैसे एसटीएलपोर्ट और कंपाइलर-मूल) के लिए संकलित / लिंक की गई साझा वस्तुओं वाली कुछ परियोजनाएं विवादों से बचने के लिए ASCIIZ के रूप में डेटा पास कर सकती हैं
Question

मैं एक std::string को char* या एक const char* कैसे परिवर्तित कर सकता हूं?




बस इसे देखें:

string str1("");
const char * str2 = str1.c_str();

हालांकि, ध्यान दें कि यह एक const char * लिए एक char * लौटाएगा, इसे किसी अन्य char सरणी में कॉपी करने के लिए strcpy का उपयोग करें।




इसे इस्तेमाल करे

std::string s(reinterpret_cast<const char *>(Data), Size);



सी ++ 17

सी ++ 17 (आगामी मानक) टेम्पलेट के basic_string को बदलता है basic_string data() एक गैर कॉन्स अधिभार data() :

charT* data() noexcept;

रिटर्न: एक पॉइंटर पी जैसे कि मैं प्रत्येक के लिए पी + i == और ऑपरेटर [0, आकार ()] में हूं।

CharT const * std::basic_string<CharT>

std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()

CharT * std::basic_string<CharT>

std::string str = { "..." };
char * p = str.data();

सी ++ 11

CharT const * std::basic_string<CharT>

std::string str = { "..." };
str.c_str();

CharT * std::basic_string<CharT>

सी ++ 11 से आगे, मानक कहता है:

  1. एक basic_string ऑब्जेक्ट में चार जैसी ऑब्जेक्ट्स को basic_string रूप से संग्रहीत किया जाएगा। यही है, किसी भी basic_string ऑब्जेक्ट के लिए, पहचान &*(s.begin() + n) == &*s.begin() + n के सभी मानों के लिए रखेगा जैसे 0 <= n < s.size()
  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    रिटर्न: *(begin() + pos) यदि pos < size() , अन्यथा मूल्य CharT() साथ CharT प्रकार के किसी ऑब्जेक्ट का संदर्भ; संदर्भित मान संशोधित नहीं किया जाएगा।

  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    रिटर्न: एक पॉइंटर पी जैसे कि p + i == &operator[](i) प्रत्येक के लिए [0,size()]

एक गैर कॉन्स चरित्र सूचक प्राप्त करने के लिए अलग-अलग संभावित तरीके हैं।

1. सी ++ 11 के संगत भंडारण का उपयोग करें

std::string foo{"text"};
auto p = &*foo.begin();

समर्थक

  • सरल और छोटा
  • तेज़ (केवल एक विधि जिसमें कोई प्रति शामिल नहीं है)

विपक्ष

  • अंतिम '\0' को गैर-कॉन्स मेमोरी का जरूरी हिस्सा नहीं बदला जाना चाहिए।

2. std::vector<CharT> प्रयोग करें

std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();

समर्थक

  • सरल
  • स्वचालित मेमोरी हैंडलिंग
  • गतिशील

विपक्ष

  • स्ट्रिंग प्रति की आवश्यकता है

3. std::array<CharT, N> उपयोग करें यदि N स्थिर समय संकलित करता है (और पर्याप्त छोटा)

std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

समर्थक

  • सरल
  • मेमोरी हैंडलिंग ढेर

विपक्ष

  • स्थिर
  • स्ट्रिंग प्रति की आवश्यकता है

4. स्वचालित भंडारण हटाने के साथ कच्चे स्मृति आवंटन

std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);

समर्थक

  • छोटी स्मृति पदचिह्न
  • स्वचालित हटाना
  • सरल

विपक्ष

  • स्ट्रिंग प्रति की आवश्यकता है
  • स्थिर (गतिशील उपयोग के लिए बहुत अधिक कोड की आवश्यकता होती है)
  • वेक्टर या सरणी से कम विशेषताएं

5. मैन्युअल हैंडलिंग के साथ कच्चे स्मृति आवंटन

std::string foo{ "text" };
char * p = nullptr;
try
{
  p = new char[foo.size() + 1u];
  std::copy(foo.data(), foo.data() + foo.size() + 1u, p);
  // handle stuff with p
  delete[] p;
}
catch (...)
{
  if (p) { delete[] p; }
  throw;
}

समर्थक

  • अधिकतम 'नियंत्रण'

चोर

  • स्ट्रिंग प्रति की आवश्यकता है
  • त्रुटियों के लिए अधिकतम देयता / संवेदनशीलता
  • जटिल



Links