आप एक एम्बेडेड नल के साथ एक std :: string का निर्माण कैसे करते हैं?


88

अगर मैं एक std :: string को एक लाइन के साथ बनाना चाहता हूँ जैसे:

std::string my_string("a\0b");

जहां मैं परिणामी स्ट्रिंग (ए, नल, बी) में तीन अक्षर रखना चाहता हूं, मुझे केवल एक ही मिलता है। उचित वाक्यविन्यास क्या है?


4
आपको इससे सावधान रहना होगा। यदि आप किसी भी संख्यात्मक चरित्र के साथ 'बी' को प्रतिस्थापित करते हैं, तो आप चुपचाप गलत स्ट्रिंग बनाएंगे। देखें: stackoverflow.com/questions/10220401/…
डेविड स्टोन

जवाबों:


128

चूंकि सी ++ 14

हम शाब्दिक निर्माण करने में सक्षम हैं std::string

#include <iostream>
#include <string>

int main()
{
    using namespace std::string_literals;

    std::string s = "pl-\0-op"s;    // <- Notice the "s" at the end
                                    // This is a std::string literal not
                                    // a C-String literal.
    std::cout << s << "\n";
}

C ++ 14 से पहले

समस्या std::stringकंस्ट्रक्टर है जो const char*मानता है कि इनपुट एक सी-स्ट्रिंग है। सी-स्ट्रिंग्स को \0समाप्त कर दिया जाता है और इस तरह \0वर्ण में पहुंचने पर पार्सिंग रुक जाती है ।

इसकी भरपाई करने के लिए, आपको कंस्ट्रक्टर का उपयोग करने की आवश्यकता है जो स्ट्रिंग सरणी से एक चार्ट बनाता है (सी-स्ट्रिंग नहीं)। यह दो पैरामीटर लेता है - सरणी और एक लंबाई के लिए एक संकेतक:

std::string   x("pq\0rs");   // Two characters because input assumed to be C-String
std::string   x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.

नोट: सी ++ std::stringहै नहीं \0 -terminated (के रूप में अन्य पदों में सुझाव दिया)। हालाँकि, आप एक आंतरिक बफ़र को पॉइंटर निकाल सकते हैं जिसमें विधि के साथ सी-स्ट्रिंग शामिल है c_str()

इसके अलावा नीचे का उपयोग करने के बारे में डौग टी के जवाब की जाँच करें vector<char>

इसके अलावा एक सी ++ 14 समाधान के लिए रियाद की जाँच करें ।


6
अद्यतन: c ++ 11 तार के रूप में अशक्त हैं। कहा जा रहा है कि, लोकी का पद वैध है।
मथेवेवरीस

14
@ मन्ना: वे भंडारण के संदर्भ में शून्य-समाप्त होते हैं, लेकिन इस अर्थ में नहीं कि वे शून्य- सार्थक अर्थपूर्ण समाप्ति (यानी स्ट्रिंग-लंबाई-परिभाषित शब्दार्थ के साथ) के साथ समाप्त होते हैं , जो शब्द का सामान्य अर्थ है।
ऑर्बिट

अच्छी तरह समझाया। धन्यवाद।
जोमा

22

यदि आप सी-स्टाइल स्ट्रिंग (वर्णों की सरणी) के साथ हेरफेर कर रहे हैं तो उपयोग करने पर विचार करें

std::vector<char>

आपके पास इसे उसी तरह से व्यवहार करने की अधिक स्वतंत्रता है जैसे आप सी-स्ट्रिंग का व्यवहार करेंगे। आप एक स्ट्रिंग में कॉपी करने के लिए कॉपी () का उपयोग कर सकते हैं:

std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());

और आप इसे कई स्थानों पर उपयोग कर सकते हैं, जहां आप सी-स्ट्रिंग्स का उपयोग कर सकते हैं

printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';

स्वाभाविक रूप से, हालांकि, आप सी-स्ट्रिंग्स जैसी समस्याओं से पीड़ित हैं। आप अपने अशक्त टर्मिनल को भूल सकते हैं या आवंटित स्थान को लिख सकते हैं।


यदि आप कह रहे हैं कि बाइट्स को स्ट्रिंग में एनकोड करने की कोशिश कर रहे हैं (जीआरसी बाइट्स को स्ट्रिंग के रूप में संग्रहीत किया जाता है) तो उत्तर में निर्दिष्ट अनुसार वेक्टर विधि का उपयोग करें; सामान्य तरीका नहीं है (नीचे देखें) जो पूरे स्ट्रिंग का निर्माण नहीं करेगा byte *bytes = new byte[dataSize]; std::memcpy(bytes, image.data, dataSize * sizeof(byte)); std::string test(reinterpret_cast<char *>(bytes)); std::cout << "Encoded String length " << test.length() << std::endl;
एलेक्स पुन्नन

13

मुझे नहीं पता कि आप ऐसा क्यों करना चाहते हैं, लेकिन यह कोशिश करें:

std::string my_string("a\0b", 3);

1
ऐसा करने के लिए आपकी चिंताएं क्या हैं? क्या आप "a \ 0b" को कभी स्टोर करने की आवश्यकता पर सवाल उठा रहे हैं? या इस तरह के भंडारण के लिए एक std :: string के उपयोग पर सवाल उठा रहे हैं? यदि उत्तरार्द्ध, आप एक विकल्प के रूप में क्या सुझाव देते हैं?
एंथनी क्रैम्प

3
यदि आप बाइनरी डेटा को एक स्ट्रिंग के रूप में संग्रहीत कर रहे हैं तो @ कॉन्स्टेंटिन तब आप कुछ गलत कर रहे हैं। यही vector<unsigned char>या unsigned char *इसके लिए आविष्कार किया गया था।
महमूद अल-कुद्सी

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

3
@DuckMaestro नहीं, यह सच नहीं है। \0UTF-8 स्ट्रिंग में एक बाइट केवल NUL हो सकता है। एक बहु-बाइट एन्कोडेड वर्ण में कभी \0भी - उस मामले के लिए कोई अन्य ASCII वर्ण नहीं होगा।
जॉन कुगेलमैन

1
एक परीक्षण मामले में एक एल्गोरिथ्म को भड़काने की कोशिश करने पर मुझे यह पता चला। तो वैध कारण हैं; यद्यपि कुछ।
namezero

12

उपयोगकर्ता द्वारा परिभाषित शाब्दिक C ++ में कौन सी नई क्षमताएं हैं? एक सुरुचिपूर्ण जवाब प्रस्तुत करता है: परिभाषित करें

std::string operator "" _s(const char* str, size_t n) 
{ 
    return std::string(str, n); 
}

तो आप इस तरह से अपनी स्ट्रिंग बना सकते हैं:

std::string my_string("a\0b"_s);

या यहां तक ​​कि:

auto my_string = "a\0b"_s;

एक "पुरानी शैली" तरीका है:

#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string

तो आप परिभाषित कर सकते हैं

std::string my_string(S("a\0b"));

8

निम्नलिखित काम करेगा ...

std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');

आपको चौकोर कोष्ठकों से बने कोष्ठकों का उपयोग करना होगा।
जे.के.

5

आपको इससे सावधान रहना होगा। यदि आप किसी भी संख्यात्मक चरित्र के साथ 'बी' की जगह लेते हैं, तो आप चुपचाप अधिकांश विधियों का उपयोग करके गलत स्ट्रिंग बनाएंगे। देखें: C ++ स्ट्रिंग शाब्दिकों के नियम नियम से बचते हैं

उदाहरण के लिए, मैंने इस मासूम दिखने वाले स्निपेट को एक कार्यक्रम के बीच में गिरा दिया

// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
    std::cerr << c;
    // 'Q' is way cooler than '\0' or '0'
    c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
    std::cerr << c;
}
std::cerr << "\n";

यहाँ मेरे लिए यह प्रोग्राम आउटपुट क्या है:

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

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

आप बहुत ही सरल के साथ एक ही समस्या प्राप्त कर सकते हैं std::string("0", 100); , लेकिन ऊपर का उदाहरण थोड़ा पेचीदा है, और इस प्रकार यह देखना मुश्किल है कि क्या गलत है।

सौभाग्य से, C ++ 11 हमें इनिशलाइज़र सूची सिंटैक्स का उपयोग करके समस्या का एक अच्छा समाधान देता है। यह आपको वर्णों की संख्या निर्दिष्ट करने से बचाता है (जो, जैसा कि मैंने ऊपर दिखाया है, आप गलत तरीके से कर सकते हैं), और बची हुई संख्याओं के संयोजन से बचते हैं। std::string str({'a', '\0', 'b'})किसी भी स्ट्रिंग सामग्री के लिए सुरक्षित है, ऐसे संस्करणों के विपरीत जो एक सरणी charऔर एक आकार लेते हैं ।


2
इस पोस्ट के लिए मेरी तैयारी के भाग के रूप में, मैं उम्मीद में जीसीसी के लिए एक बग रिपोर्ट प्रस्तुत कि वे इस एक छोटे से सुरक्षित बनाने के लिए एक चेतावनी जोड़ देगा: gcc.gnu.org/bugzilla/show_bug.cgi?id=54924
डेविड स्टोन

4

C ++ 14 में अब आप शाब्दिक उपयोग कर सकते हैं

using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3

1
और दूसरी पंक्ति वैकल्पिक रूप से, अधिक अच्छी तरह से लिखी जा सकती है, जैसेauto s{"a\0b"s};
अंडरस्कोर_ड

अच्छा जवाब धन्यवाद।
जोमा


1

अनाम का उत्तर उत्कृष्ट है, लेकिन C ++ 98 में एक गैर-मैक्रो समाधान भी है:

template <size_t N>
std::string RawString(const char (&ch)[N])
{
  return std::string(ch, N-1);  // Again, exclude trailing `null`
}

इस फ़ंक्शन के साथ, RawString(/* literal */)समान स्ट्रिंग का उत्पादन करेगा S(/* literal */):

std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;

इसके अतिरिक्त, मैक्रो के साथ एक समस्या है: अभिव्यक्ति वास्तव में एक std::stringलिखित के रूप में नहीं है, और इसलिए इसका उपयोग साधारण असाइनमेंट-प्रारंभिक शिक्षा के लिए नहीं किया जा सकता है:

std::string s = S("a\0b"); // ERROR!

... तो यह उपयोग करने के लिए बेहतर हो सकता है:

#define std::string(s, sizeof s - 1)

स्पष्ट रूप से आपको अपनी परियोजना में केवल एक या दूसरे समाधान का उपयोग करना चाहिए और जो कुछ भी उचित लगता है उसे कॉल करें।


-5

मुझे पता है कि यह प्रश्न पूछे जाने का समय है। लेकिन जिस किसी को भी इसी तरह की समस्या हो रही है उसके लिए निम्नलिखित कोड में रुचि हो सकती है।

CComBSTR(20,"mystring1\0mystring2\0")

यह उत्तर Microsoft प्लेटफ़ॉर्म के लिए बहुत विशिष्ट है और मूल प्रश्न (जो std :: string के बारे में पूछा गया है) को संबोधित नहीं करता है।
जून रोड्स

-8

लगभग सभी std :: स्ट्रिंग्स के कार्यान्वयन को समाप्त कर दिया गया है, इसलिए शायद आपको ऐसा नहीं करना चाहिए। ध्यान दें कि "a \ 0b" वास्तव में स्वचालित नल टर्मिनेटर (a, null, b, null) के कारण चार वर्ण लंबा है। यदि आप वास्तव में ऐसा करना चाहते हैं और std :: string का अनुबंध तोड़ सकते हैं, तो आप कर सकते हैं:

std::string s("aab");
s.at(1) = '\0';

लेकिन अगर आप करते हैं, तो आपके सभी दोस्त आप पर हंसेंगे, आपको सच्ची खुशी कभी नहीं मिलेगी।


1
std :: स्ट्रिंग को पूर्ण रूप से समाप्त करने की आवश्यकता नहीं है।
मार्टिन यॉर्क

2
इसकी आवश्यकता नहीं है, लेकिन लगभग सभी कार्यान्वयनों में, यह संभवत: c_str () एक्सेसर की आवश्यकता के कारण आपको अशक्त समतुल्य प्रदान करने के लिए है।
जयंती

2
दक्षता के लिए एक अशक्त चरित्र को डाटा बफर के पीछे रखा जा सकता है। लेकिन एक स्ट्रिंग पर कोई भी ऑपरेशन (अर्थात विधियाँ) इस ज्ञान का उपयोग नहीं करता है या NULL वर्ण वाले स्ट्रिंग से प्रभावित होता है। NULL वर्ण को ठीक उसी तरह से हेरफेर किया जाएगा जैसे कि कोई अन्य वर्ण।
मार्टिन यॉर्क

यही कारण है कि यह बहुत अजीब है कि स्ट्रिंग std :: - इसका व्यवहार किसी भी मंच पर परिभाषित नहीं है।

काश user595447 अभी भी यहाँ था ताकि मैं उनसे पूछ सकूँ कि पृथ्वी पर वे क्या सोचते थे कि वे किस बारे में बात कर रहे थे।
अंडरस्कोर_ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.