كيف يمكنك إنشاء std::string مع قيمة فارغة مضمنة؟

StackOverflow https://stackoverflow.com/questions/164168

  •  03-07-2019
  •  | 
  •  

سؤال

إذا كنت أرغب في إنشاء std::string بخط مثل:

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

عندما أرغب في الحصول على ثلاثة أحرف في السلسلة الناتجة (a، null، b)، أحصل على حرف واحد فقط.ما هو بناء الجملة الصحيح؟

هل كانت مفيدة؟

المحلول

منذ C++ 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* يفترض أن الإدخال عبارة عن سلسلة C.سلاسل C هي \0 تم إنهاؤه وبالتالي يتوقف التحليل عندما يصل إلى \0 شخصية.

للتعويض عن ذلك، تحتاج إلى استخدام المُنشئ الذي يبني السلسلة من مصفوفة char (وليس سلسلة C).يتطلب هذا معلمتين - مؤشر للمصفوفة وطول:

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- تم إنهاؤه (كما هو مقترح في مشاركات أخرى).ومع ذلك، يمكنك استخراج مؤشر إلى مخزن مؤقت داخلي يحتوي على سلسلة C باستخدام الطريقة c_str().

تحقق أيضا إجابة دوغ تي أدناه حول استخدام أ vector<char>.

تحقق أيضا رياض د للحصول على حل C++ 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';

وبطبيعة الحال، ومع ذلك، كنت تعاني من نفس المشاكل ج-السلاسل. قد ننسى محطة فارغة أو كتابة الماضي المساحة المخصصة.

وليس لدي أي فكرة <م> لماذا كنت تريد أن تفعل شيء من هذا القبيل، ولكن حاول هذا:

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

<وأ href = "https://stackoverflow.com/questions/237804/user-defined-literals-in-c11-a-much-needed-addition-or-making-c-even-more-b" > ماذا قدرات جديدة لم الحرفية المعرفة من قبل المستخدم إضافة إلى 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

وكان هذا أول بيان طبعتي مرتين، عدة شخصيات غير المطبوعة، يليه سطر جديد، تليها شيء في الذاكرة الداخلية، وأنا فقط overwrote (ومن ثم طباعتها، وتبين أن تمت الكتابة عليه). الأسوأ من ذلك كله، وحتى إعداد هذا مع دول مجلس التعاون الخليجي شامل ومطول تحذيرات أعطاني ما يدل على كون شيء خاطئ، ويعمل البرنامج من خلال valgrind لا يشكو أي أنماط الوصول إلى الذاكرة غير لائقة. وبعبارة أخرى، فإنه لا يمكن الكشف عنها تماما من الأدوات الحديثة.

ويمكنك الحصول على نفس هذه المشكلة مع 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

والأفضل استخدام الأمراض المنقولة جنسيا :: ناقلات <شار> إذا كان هذا السؤال هو ليس فقط للأغراض التعليمية.

والجواب مجهول هي ممتازة، ولكن هناك حل غير الماكرو في 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")

وتقريبا جميع الأجهزة من الأمراض المنقولة جنسيا :: سلاسل باطلة منتهية، لذلك ربما كنت لا ينبغي القيام بذلك. لاحظ أن "ل\ 0B" هو في الواقع أربعة أحرف بسبب فاصل لاغية التلقائي (أ، فارغة، ب، لاغية). إذا كنت تريد حقا أن تفعل هذا وكسر عقد STD :: سلسلة، يمكنك القيام به:

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

ولكن إذا قمت بذلك، فإن جميع أصدقائك يضحكون عليك، أنك لن تجد السعادة الحقيقية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top