अगर मैं एक std :: string को एक लाइन के साथ बनाना चाहता हूँ जैसे:
std::string my_string("a\0b");
जहां मैं परिणामी स्ट्रिंग (ए, नल, बी) में तीन अक्षर रखना चाहता हूं, मुझे केवल एक ही मिलता है। उचित वाक्यविन्यास क्या है?
अगर मैं एक std :: string को एक लाइन के साथ बनाना चाहता हूँ जैसे:
std::string my_string("a\0b");
जहां मैं परिणामी स्ट्रिंग (ए, नल, बी) में तीन अक्षर रखना चाहता हूं, मुझे केवल एक ही मिलता है। उचित वाक्यविन्यास क्या है?
जवाबों:
हम शाब्दिक निर्माण करने में सक्षम हैं 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";
}
समस्या 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 समाधान के लिए रियाद की जाँच करें ।
यदि आप सी-स्टाइल स्ट्रिंग (वर्णों की सरणी) के साथ हेरफेर कर रहे हैं तो उपयोग करने पर विचार करें
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;
मुझे नहीं पता कि आप ऐसा क्यों करना चाहते हैं, लेकिन यह कोशिश करें:
std::string my_string("a\0b", 3);
vector<unsigned char>
या unsigned char *
इसके लिए आविष्कार किया गया था।
std::string
यह इंगित करने के लिए उपयोग करता हूं कि डेटा को सादे-पाठ के रूप में माना जाना चाहिए, लेकिन मैं कुछ हैशिंग काम कर रहा हूं और मैं यह सुनिश्चित करना चाहता हूं कि अभी भी सब कुछ शामिल है जो अशक्त पात्रों के साथ काम करता है। यह एक एम्बेडेड नल चरित्र के साथ एक स्ट्रिंग शाब्दिक के एक वैध उपयोग की तरह लगता है।
\0
UTF-8 स्ट्रिंग में एक बाइट केवल NUL हो सकता है। एक बहु-बाइट एन्कोडेड वर्ण में कभी \0
भी - उस मामले के लिए कोई अन्य ASCII वर्ण नहीं होगा।
उपयोगकर्ता द्वारा परिभाषित शाब्दिक 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"));
निम्नलिखित काम करेगा ...
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
आपको इससे सावधान रहना होगा। यदि आप किसी भी संख्यात्मक चरित्र के साथ 'बी' की जगह लेते हैं, तो आप चुपचाप अधिकांश विधियों का उपयोग करके गलत स्ट्रिंग बनाएंगे। देखें: 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
और एक आकार लेते हैं ।
C ++ 14 में अब आप शाब्दिक उपयोग कर सकते हैं
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
auto s{"a\0b"s};
यदि यह प्रश्न केवल शैक्षिक उद्देश्यों के लिए नहीं है तो std :: वेक्टर <char> का उपयोग करना बेहतर है।
अनाम का उत्तर उत्कृष्ट है, लेकिन 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)
स्पष्ट रूप से आपको अपनी परियोजना में केवल एक या दूसरे समाधान का उपयोग करना चाहिए और जो कुछ भी उचित लगता है उसे कॉल करें।
मुझे पता है कि यह प्रश्न पूछे जाने का समय है। लेकिन जिस किसी को भी इसी तरह की समस्या हो रही है उसके लिए निम्नलिखित कोड में रुचि हो सकती है।
CComBSTR(20,"mystring1\0mystring2\0")
लगभग सभी std :: स्ट्रिंग्स के कार्यान्वयन को समाप्त कर दिया गया है, इसलिए शायद आपको ऐसा नहीं करना चाहिए। ध्यान दें कि "a \ 0b" वास्तव में स्वचालित नल टर्मिनेटर (a, null, b, null) के कारण चार वर्ण लंबा है। यदि आप वास्तव में ऐसा करना चाहते हैं और std :: string का अनुबंध तोड़ सकते हैं, तो आप कर सकते हैं:
std::string s("aab");
s.at(1) = '\0';
लेकिन अगर आप करते हैं, तो आपके सभी दोस्त आप पर हंसेंगे, आपको सच्ची खुशी कभी नहीं मिलेगी।