Bil*_*ill 82 c++ null stdstring
如果我想构造一个std :: string,其行如下:
std::string my_string("a\0b");
Run Code Online (Sandbox Code Playgroud)
我希望在结果字符串中有三个字符(a,null,b),我只得到一个.什么是正确的语法?
Mar*_*ork 123
我们已经能够创建文字 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";
}
Run Code Online (Sandbox Code Playgroud)
问题是std::string构造函数const char*假设输入是C字符串.C字符串被\0终止,因此解析在到达\0字符时停止.
为了弥补这一点,您需要使用从char数组(而不是C-String)构建字符串的构造函数.这需要两个参数 - 指向数组的指针和一个长度:
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.
Run Code Online (Sandbox Code Playgroud)
注意:C++ std::string是不 \0封端的(如在其他职位的建议).但是,您可以使用该方法提取指向包含C-String的内部缓冲区的指针c_str().
另请参阅Doug T关于使用a 的回答vector<char>.
另请参阅RiaD以获取C++ 14解决方案.
Dou*_* T. 22
如果您正在使用c风格的字符串(字符数组)进行操作,请考虑使用
std::vector<char>
Run Code Online (Sandbox Code Playgroud)
您可以更自由地像处理数组一样对待它,就像对待c字符串一样.您可以使用copy()复制到字符串中:
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
Run Code Online (Sandbox Code Playgroud)
你可以在许多相同的地方使用它,你可以使用c字符串
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
Run Code Online (Sandbox Code Playgroud)
然而,自然地,您遇到与c弦相同的问题.您可能会忘记空终端或写入已分配的空间.
17 *_* 26 13
我不知道你为什么要做这样的事情,但试试这个:
std::string my_string("a\0b", 3);
Run Code Online (Sandbox Code Playgroud)
小智 12
用户定义的文字为C++添加了哪些新功能?提出一个优雅的答案:定义
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
Run Code Online (Sandbox Code Playgroud)
然后你可以这样创建你的字符串:
std::string my_string("a\0b"_s);
Run Code Online (Sandbox Code Playgroud)
甚至是这样的:
auto my_string = "a\0b"_s;
Run Code Online (Sandbox Code Playgroud)
有一种"旧式"方式:
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
Run Code Online (Sandbox Code Playgroud)
然后你可以定义
std::string my_string(S("a\0b"));
Run Code Online (Sandbox Code Playgroud)
以下将有效......
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
Run Code Online (Sandbox Code Playgroud)
在 C++14 中,您现在可以使用文字
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
Run Code Online (Sandbox Code Playgroud)
你必须要小心这一点.如果用任何数字字符替换'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";
Run Code Online (Sandbox Code Playgroud)
以下是此程序为我输出的内容:
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
Run Code Online (Sandbox Code Playgroud)
这是我的第一次打印声明两次,几个非打印字符,接着是换行符,然后是内部存储器中的内容,我刚刚覆盖(然后打印,显示它已被覆盖).最糟糕的是,即使用彻底和冗长的gcc警告编译它也没有给出任何错误的迹象,并且通过valgrind运行程序并没有抱怨任何不正确的内存访问模式.换句话说,现代工具完全无法检测到它.
你可以用更简单的方法解决同样的问题std::string("0", 100);,但上面的例子有点棘手,因此很难看出错误.
幸运的是,C++ 11使用初始化列表语法为我们提供了一个很好的解决方案.这使您无需指定字符数(如上所示,您可以正确执行),并避免组合转义的数字.std::string str({'a', '\0', 'b'})对于任何字符串内容都是安全的,与采用数组char和大小的版本不同.