कहते हैं ...
std::string x = "hello";
एक `स्ट्रिंग` से` चार * `या` कास्ट चार * `प्राप्त करना
वर्ण पॉइंटर कैसे प्राप्त करें जो कि x
दायरे में रहते हुए मान्य है और आगे संशोधित नहीं किया गया है
सी ++ 11 चीजों को सरल करता है; निम्नलिखित सभी एक ही आंतरिक स्ट्रिंग बफर तक पहुंच प्रदान करते हैं:
const char* p_c_str = x.c_str();
const char* p_data = x.data();
char* p_writable_data = x.data(); // for non-const x from C++17
const char* p_x0 = &x[0];
char* p_x0_rw = &x[0]; // compiles iff x is not const...
उपरोक्त सभी संकेत एक ही मान रखेंगे - बफर में पहले वर्ण का पता। यहां तक कि एक खाली स्ट्रिंग में "बफर में पहला चरित्र" होता है, क्योंकि C ++ 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
पॉइंटर p_writable_data
और से के लिए &x[0]
:
p_writable_data[n] = c;
p_x0_rw[n] = c; // valid for n <= x.size() - 1
// i.e. don't overwrite the implementation maintained NUL
स्ट्रिंग में कहीं और NUL लिखने से 's' नहीं बदलता है ; किसी भी संख्या में NUL को सम्मिलित करने की अनुमति है - उन्हें कोई विशेष उपचार नहीं दिया जाता है (उसी C ++ 03 में)।string
size()
string
std::string
में सी ++ 03 , चीजें काफी अधिक जटिल थे (मुख्य अंतर पर प्रकाश डाला ):
x.data()
const char*
स्ट्रिंग के आंतरिक बफ़र पर लौटता है जिसे एनयूएल के साथ समाप्त करने के लिए मानक द्वारा आवश्यक नहीं था (यानी ['h', 'e', 'l', 'l', 'o']
अनधिकृत या कचरा मूल्यों के साथ हो सकता है , आकस्मिक पहुंच के साथ अपरिभाषित व्यवहार होता है )।
x.size()
वर्णों को पढ़ने के सुरक्षित हैं, यानी x[0]
के माध्यम सेx[x.size() - 1]
- खाली स्ट्रिंग्स के लिए, आपको कुछ गैर-NULL पॉइंटर की गारंटी दी जाती है, जिसमें 0 को सुरक्षित रूप से जोड़ा जा सकता है (hurray!), लेकिन आपको उस पॉइंटर को डिरेल नहीं करना चाहिए।
&x[0]
- खाली तारों के लिए इसका अपरिभाषित व्यवहार है (21.3.4)
- उदाहरण के लिए,
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
आपको f(&x[0], x.size());
तब कॉल नहीं करना चाहिए जब x.empty()
- बस उपयोग करें f(x.data(), ...)
।
- अन्यथा,
x.data()
लेकिन प्रति के रूप में :
- गैर के लिए -
const
x
यह एक गैर- const
char*
सूचक देता है; आप स्ट्रिंग सामग्री को अधिलेखित कर सकते हैं
x.c_str()
- रिटर्न
const char*
एक ASCIIZ को (NUL-समाप्त) मूल्य का प्रतिनिधित्व (यानी [ 'ज', 'ई', 'एल', 'एल', 'ओ', '\ 0'])।
- हालांकि कुछ यदि कोई कार्यान्वयन ऐसा करने के लिए चुना है, सी ++ 03 स्टैंडर्ड स्ट्रिंग कार्यान्वयन एक बनाने की स्वतंत्रता दे करने के लिए शब्दों में किया गया था अलग NUL-समाप्त बफर मक्खी पर , संभावित गैर NUL से बफर द्वारा "उजागर" समाप्त
x.data()
और&x[0]
x.size()
+ 1 वर्ण पढ़ने के लिए सुरक्षित हैं।
- खाली स्ट्रिंग्स (['0']) के लिए भी सुरक्षित गारंटी।
कानूनी सूचकांकों के बाहर पहुँचने के परिणाम
जिस भी तरह से आपको एक पॉइंटर मिलता है, आपको पॉइंटर से आगे मेमोरी की एक्सेस नहीं करनी चाहिए। ऐसा करने के प्रयासों में अपरिभाषित व्यवहार होता है , आवेदन के दुर्घटनाओं और कचरे के परिणामों की बहुत वास्तविक संभावना के साथ, यहां तक कि रीड के लिए, और इसके अतिरिक्त थोक डेटा, स्टैक भ्रष्टाचार और / या सुरक्षा कमजोरियों के लिए लिखते हैं।
उन बिंदुओं को कब अमान्य किया जाता है?
यदि आप कुछ string
सदस्य फ़ंक्शन को कॉल करते हैं, जो string
आगे की क्षमता को संशोधित करता है या सुरक्षित रखता है, तो उपरोक्त तरीकों में से किसी भी तरीके से पहले से लौटाए गए कोई भी पॉइंटर मान अमान्य हैं । आप अन्य पॉइंटर प्राप्त करने के लिए उन विधियों का फिर से उपयोग कर सकते हैं। (नियम पुनरावृत्तियों के लिए समान हैं string
)।
यह भी देखें कि x
पत्तियों के दायरे के बाद भी वर्ण सूचक को कैसे मान्य किया जाए या नीचे और संशोधित किया जाए ...।
तो, कौन सा उपयोग करना बेहतर है?
C ++ 11 से, .c_str()
ASCIIZ डेटा के लिए, और .data()
"बाइनरी" डेटा के लिए उपयोग करें (नीचे और नीचे समझाया गया है)।
सी ++ 03 में, उपयोग .c_str()
जब तक निश्चित है कि .data()
पर्याप्त है, और पसंद करते हैं .data()
अधिक &x[0]
के रूप में यह रिक्त स्ट्रिंग के लिए सुरक्षित है ....
... data()
उचित होने पर उपयोग करने के लिए प्रोग्राम को समझने की कोशिश करें , या आप शायद अन्य गलतियाँ करेंगे ...
ASCII NUL '0' वर्ण की गारंटी .c_str()
प्रासंगिक और सुरक्षित करने के लिए उपयोग डेटा के अंत denoting एक प्रहरी मूल्य के रूप में कई कार्यों द्वारा किया जाता है। यह C ++ दोनों पर लागू होता है - केवल फ़ंक्शन fstream::fstream(const char* filename, ...)
और साझा-के-सी फ़ंक्शन जैसे कार्य करता है strchr()
, और printf()
।
दिए .c_str()
गए बफर के बारे में सी ++ 03 की गारंटी देता है कि यह एक सुपर-सेट है .data()
, आप हमेशा सुरक्षित रूप से उपयोग कर सकते हैं .c_str()
, लेकिन लोग इसे पसंद नहीं करते हैं:
.data()
स्रोत कोड को पढ़ने वाले अन्य प्रोग्रामर को संचार का उपयोग करते हुए कि डेटा ASCIIZ नहीं है (बल्कि, आप स्ट्रिंग का उपयोग डेटा के एक ब्लॉक को स्टोर करने के लिए कर रहे हैं (जो कभी-कभी सच में शाब्दिक नहीं है)), या कि आप इसे पास कर रहे हैं एक अन्य फ़ंक्शन जो इसे "बाइनरी" डेटा के ब्लॉक के रूप में मानता है। यह सुनिश्चित करने में एक महत्वपूर्ण अंतर्दृष्टि हो सकती है कि अन्य प्रोग्रामर के कोड परिवर्तन डेटा को ठीक से संभालना जारी रखें।
- C ++ 03 केवल: इस बात की थोड़ी संभावना है कि आपके
string
कार्यान्वयन को NUL समाप्त बफर तैयार करने के लिए कुछ अतिरिक्त मेमोरी आवंटन और / या डेटा कॉपी करने की आवश्यकता होगी।
एक और संकेत के रूप में, यदि किसी फ़ंक्शन के मापदंडों की आवश्यकता होती है ( const
), 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);
अ char*
या से const char*
उत्पन्न होने के लिए अन्य कारणstring
तो, ऊपर आपने देखा है कि मूल ( const
) से char*
स्वतंत्र पाठ की प्रतिलिपि कैसे बनाई जाती है string
, लेकिन आप इसके बारे में क्या कर सकते हैं ? उदाहरणों का एक बेतरतीब ख़ुशामद ...
- "C" कोड को C ++
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;
) के लिए उपयोग की जाने वाली वाष्पशील मेमोरी द्वारा निर्दिष्ट बफ़र पर पाठ की प्रतिलिपि बनाएँ
- संलग्न
x
एक चरित्र सरणी के पाठ पहले से ही कुछ ASCIIZ पाठ (जैसे युक्त strcat(other_buffer, x.c_str())
) - बफर लंघन के प्रति सावधान रहें (कई स्थितियों में आप उपयोग करना पड़ सकता है strncat
)
- एक वापसी
const char*
या char*
एक समारोह से (ऐतिहासिक कारणों से शायद - ग्राहक के अपने मौजूदा एपीआई का उपयोग कर - या सी अनुकूलता के लिए आप एक वापस जाने के लिए नहीं करना चाहते हैं std::string
, लेकिन अपने नकल करना चाहते हैं string
फोन करने वाले के लिए के डेटा कहीं)
- एक पॉइंटर को वापस न करने के लिए सावधान रहें
string
जो एक स्थानीय चर के बाद कॉल करने वाले द्वारा डिरेल्ड हो सकता है, जिसमें उस पॉइंटर ने बाएं स्कोप को छोड़ दिया है
- अलग-अलग
std::string
कार्यान्वयन के लिए संकलित / साझा की गई साझा वस्तुओं के साथ कुछ परियोजनाएं (जैसे STLport और संकलक-मूल) संघर्षों से बचने के लिए ASCIIZ के रूप में डेटा पारित कर सकती हैं।