আপনি এমবেডড নাল দিয়ে স্ট্যান্ড :: স্ট্রিংটি কীভাবে তৈরি করবেন?


89

আমি যদি একটি লাইনের সাথে একটি স্ট্যান্ড :: স্ট্রিং তৈরি করতে চাই তবে:

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

যেখানে আমি ফলস্বরূপ স্ট্রিংয়ে তিনটি অক্ষর রাখতে চাই (ক, নাল, খ), আমি কেবল একটি পেয়েছি। সঠিক বাক্য গঠন কী?


4
আপনি এই সম্পর্কে যত্নবান হতে হবে। যদি আপনি 'বি' কে কোনও সংখ্যার অক্ষরের সাথে প্রতিস্থাপন করেন তবে আপনি নিঃশব্দে ভুল স্ট্রিং তৈরি করবেন। দেখুন: stackoverflow.com/questions/10220401/…
ডেভিড স্টোন

উত্তর:


129

যেহেতু সি ++ 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";
}

সি ++ এর আগে

সমস্যাটি এমন 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 সমাধান জন্য।


8
আপডেট: সি ++ এর মতো 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);

4
এটি করার জন্য আপনার উদ্বেগগুলি কী? আপনি কি কখনও "a \ 0b" সঞ্চয় করার প্রয়োজনীয়তা নিয়ে প্রশ্ন করছেন? বা এই জাতীয় স্টোরেজের জন্য স্টাডি :: স্ট্রিংয়ের ব্যবহার সম্পর্কে প্রশ্নবিদ্ধ? যদি পরেরটি হয়, তবে বিকল্প হিসাবে আপনি কী পরামর্শ করবেন?
অ্যান্টনি ক্র্যাম্প 0

4
@ কনস্ট্যান্টিন তখন আপনি কিছু ভুল করছেন যদি আপনি স্ট্রিং হিসাবে বাইনারি ডেটা সংরক্ষণ করেন। এটিই vector<unsigned char>বা এর unsigned char *জন্য আবিষ্কার করা হয়েছিল।
মাহমুদ আল-কুদসি

4
স্ট্রিংগুলির সুরক্ষা সম্পর্কে আরও জানার চেষ্টা করার সময় আমি এটি পেরিয়ে এসেছি। আমি আমার কোডটি পরীক্ষা করে দেখতে চেয়েছিলাম যে এটি এখনও কাজ করে তা নিশ্চিত করেও যদি এটি কোনও ফাইল / নেটওয়ার্ক থেকে পাঠ্য ডেটা হওয়ার প্রত্যাশা করে তখন কোনও শূন্য চরিত্র পড়ে। আমি std::stringতথ্যটি প্লেইন-পাঠ্য হিসাবে বিবেচনা করা উচিত তা বোঝাতে ব্যবহার করি তবে আমি কিছু হ্যাশিংয়ের কাজ করছি এবং আমি নিশ্চিত করতে চাই যে জড়িত শূন্য চরিত্রগুলির সাথে এখনও সমস্ত কিছু কাজ করে। এটি এম্বেডড নাল চরিত্রের সাথে একটি স্ট্রিং আক্ষরিকের বৈধ ব্যবহারের মতো বলে মনে হচ্ছে।
ডেভিড স্টোন

4
@ ডাকমাস্টো না, এটি সত্য নয়। \0UTF-8 স্ট্রিংয়ের একটি বাইট কেবল NUL হতে পারে। একটি মাল্টি বাইট এনকোডেড অক্ষর কখনই থাকতে পারে না - \0এই বিষয়ে অন্য কোনও ASCII অক্ষর নেই।
জন কুগেলম্যান

4
একটি পরীক্ষার ক্ষেত্রে অ্যালগরিদমকে উস্কে দেওয়ার চেষ্টা করার সময় আমি এটি পেরিয়ে এসেছি। সুতরাং বৈধ কারণ আছে; যদিও কিছু।
নেমজারো

12

ব্যবহারকারী-সংজ্ঞায়িত আক্ষরিকাগুলি সি ++ এ কী নতুন ক্ষমতা যুক্ত করে? একটি মার্জিত উত্তর উপস্থাপন করুন: সংজ্ঞায়িত করুন

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"));


5

আপনি এই সম্পর্কে যত্নবান হতে হবে। যদি আপনি 'বি' কে কোনও সংখ্যাসূচক অক্ষরের সাথে প্রতিস্থাপন করেন তবে আপনি বেশিরভাগ পদ্ধতি ব্যবহার করে নিঃশব্দে ভুল স্ট্রিং তৈরি করবেন। দেখুন: সি ++ স্ট্রিং আক্ষরিক জন্য পালনের চরিত্রের নিয়ম

উদাহরণস্বরূপ, আমি এই প্রোগ্রামের মাঝখানে এই নিরীহ চেহারা স্নিপেটটি ফেলে দিয়েছি

// 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);তবে উপরের উদাহরণটি একটি সামান্য কৌশলযুক্ত এবং কী ভুল তা দেখতে আরও শক্ত er

ভাগ্যক্রমে, সি ++ 11 ইনিশিয়ালার তালিকা সিনট্যাক্স ব্যবহার করে সমস্যার একটি ভাল সমাধান দেয়। এটি আপনাকে অক্ষরের সংখ্যা নির্দিষ্ট করা থেকে বাঁচায় (যা আমি উপরে দেখিয়েছি, আপনি ভুলভাবে করতে পারেন), এবং পালানো সংখ্যার সমন্বয় এড়ানো যায় avo std::string str({'a', '\0', 'b'})যে কোনও স্ট্রিং সামগ্রীর জন্য সুরক্ষিত, সংস্করণগুলির চেয়ে আলাদা যা কোনও অ্যারে charএবং আকার নেয়।


4
এই পোস্টের জন্য আমার প্রস্তুতি অংশ হিসেবে, আমি আশা জিসিসি করার জন্য একটি বাগ রিপোর্ট পেশ করে যে তারা এই একটি সামান্য আরো নিরাপদ করতে একটি সতর্কতা যোগ হবে: gcc.gnu.org/bugzilla/show_bug.cgi?id=54924
ডেভিড স্টোন

4

সি ++ 14 এ আপনি এখন আক্ষরিক ব্যবহার করতে পারেন

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

4
এবং ২ য় লাইনটি বিকল্পভাবে আরও বেশি সুন্দরভাবে লেখা যেতে পারে, যেমনauto s{"a\0b"s};
আন্ডারস্কোর_

সুন্দর উত্তর ধন্যবাদ।
জোমা


1

বেনামের উত্তরটি দুর্দান্ত, তবে সি ++ 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")

এই উত্তরটি মাইক্রোসফ্ট প্ল্যাটফর্মগুলির জন্য খুব নির্দিষ্ট এবং মূল প্রশ্নটি (যা স্টাডি :: স্ট্রিং সম্পর্কে জিজ্ঞাসা করেছিল) সম্বোধন করে না।
জুন রোডস

-8

স্ট্যান্ড :: স্ট্রিংয়ের প্রায় সমস্ত বাস্তবায়ন বাতিল-সমাপ্ত, সুতরাং আপনার সম্ভবত এটি করা উচিত নয়। নোট করুন যে স্বয়ংক্রিয় নাল টার্মিনেটর (এ, নাল, বি, নাল) এর কারণে "a \ 0b" আসলে চারটি অক্ষর দীর্ঘ long আপনি যদি সত্যিই এটি করতে এবং std :: স্ট্রিংয়ের চুক্তিটি ভাঙতে চান তবে আপনি এটি করতে পারেন:

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

তবে আপনি যদি করেন তবে আপনার সমস্ত বন্ধুরা আপনাকে উপহাস করবে, আপনি কখনই সত্যিকারের সুখ পাবেন না।


4
std :: স্ট্রিং NULL সমাপ্ত করার প্রয়োজন হয় না।
মার্টিন ইয়র্ক

4
এটি প্রয়োজন হয় না, তবে প্রায় সমস্ত বাস্তবায়নের মধ্যেই সম্ভবত এটি আপনাকে সিদ্ধ সমাপ্ত সমতুল্য সরবরাহের জন্য সি_এসটার () অ্যাক্সেসরের প্রয়োজন হয়।
জার্নি

4
দক্ষতার জন্য একটি নাল অক্ষর ডেটা বাফারের পিছনে রাখা যেতে পারে। তবে স্ট্রিংয়ের কোনও ক্রিয়াকলাপ (অর্থাত্ পদ্ধতিগুলি) এই জ্ঞানটি ব্যবহার করে না বা কোনও NULL অক্ষরযুক্ত স্ট্রিং দ্বারা প্রভাবিত হয়। NULL চরিত্রটি অন্য চরিত্রের মতো ঠিক একইভাবে চালিত হবে।
মার্টিন ইয়র্ক

এই কারণেই এটি এত মজাদার যে স্ট্রিংটি std :: - এর আচরণটি কোনও প্ল্যাটফর্মে সংজ্ঞায়িত করা হয়নি।

আমি আশা করি ব্যবহারকারীর 95৯৫৪7 still এখনও এখানে থাকুক যাতে আমি তাদের জিজ্ঞাসা করতে পারি পৃথিবীতে তারা কী ভেবেছিল তা তারা বলছে।
আন্ডারস্কোর_২
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.