Если я использую std::reverse
для переменной std::string
, могу ли я смело предположить, что нулевой символ '\0'
будет помещен в начале строки?
С++ 14 - Есть ли std:: reverse (ed) std::string с нулевым символом в начале?
Ответ 1
Нет, он не будет содержать байт NUL (если вы не поместите его там). Первой итератор не будет содержать байта NUL, он будет перебирать только символы в самой строке.
Байт NUL, по-видимому, будет проходить до конца .c_str()
или .data()
.
Пример программы:
#include <string>
#include <iostream>
#include <algorithm>
int main() {
std::string s = "Hello";
std::cout << "Forwards:\n";
for (auto i = std::begin(s), e = std::end(s); i != e; ++i) {
std::cout << *i << ' ' << static_cast<int>(*i) << '\n';
}
std::cout << "Backwards:\n";
std::reverse(std::begin(s), std::end(s));
for (auto i = std::begin(s), e = std::end(s); i != e; ++i) {
std::cout << *i << ' ' << static_cast<int>(*i) << '\n';
}
return 0;
}
Вывод:
Forwards: H 72 e 101 l 108 l 108 o 111 Backwards: o 111 l 108 l 108 e 101 H 72
Ответ 2
В отличие от большинства контейнеров, std::string
имеет данные под итератором end()
. (Стандарт делает разыменование end()
еще незаконным, но на самом деле нет способа его избежать).
A std::string
of .size()=N
имеет N+1
записи, последним из которых является '\0'
. Первые записи N
также могут содержать '\0'
s, но последняя добавляется автоматически.
begin()
возвращает итератор в первую запись и end()
в один конец прошлого (фактически, к завершающему '\0'
, но вам не разрешено проверять это по стандарту (что означает отладочные итераторы могут поймать эту ошибку и сказать, что вы ее сделали)).
Между тем, .data()
и .c_str()
возвращают указатели на необработанный буфер. С .c_str()
, читающим '\0'
"за конец", является законным. Любопытно, что с .data()
не законно читать '\0'
за конец строки, так как разрешено читать только те элементы, которые могут быть итерированы. Это законно по стандарту, но маловероятно, что будет неинициализированный характер (или даже ошибка страницы), где '\0'
будет до первого вызова .c_str()
. Также не разрешено выделять в С++ 11. (Я не делаю никаких гарантий относительно С++ 03 или более ранних версий С++).
rbegin()
и rend()
таким образом также возвращают элементы внутри строки, не считая, что завершающие '\0'
и reverse(begin(), end())
снова работают с элементами внутри строки, не считая завершающего '\0'
.
Если вы вставляете '\0'
в строку, это не приведет к завершению строки. Если вы передадите API .c_str()
в const char*
, он предположит, что строка завершена, но фактический буфер, управляемый std::string
, пройдет мимо введенного '\0'
. И end()
будет продолжать ссылаться на элемент "один минус последний" строки, а не на ваш '\0'
.
Ответ 3
Можно ли смело предположить, что нулевой символ '\ 0' будет помещен в начале строки?
Нет. Это будет иметь место только в том случае, если вы поместили нулевой символ в качестве окончательного символа исходной строки.
Ответ 4
A std::string не будет содержать завершающий нулевой символ, вы думаете о нулевом концевом массиве char, который используется как строка.