Использование нулевого символа в строках (С++)
Я очищаю свой С++ и наткнулся на любопытное поведение в отношении строк, массивов символов и нулевого символа ('\0'
). Следующий код:
#include <iostream>
using namespace std;
int main() {
cout << "hello\0there"[6] << endl;
char word [] = "hello\0there";
cout << word[6] << endl;
string word2 = "hello\0there";
cout << word2[6] << endl;
return 0;
}
выводит результат:
> t
> t
>
Что происходит за кулисами? Почему строковый литерал и объявленный массив char хранят 't'
в индексе 6 (после внутреннего '\0'
), но объявленная строка не работает?
Ответы
Ответ 1
Из того, что я помню, первые два по существу представляют собой только массив, а способ печати строки - продолжать печатать до тех пор, пока не встретится \0
. Таким образом, в первых двух примерах вы начинаете с смещения точки 6-го символа в строке, но в вашем случае вы печатаете 6-й символ, который равен t
.
Что происходит с классом string
, так это то, что он копирует строку в свой собственный внутренний буфер и делает это, копируя строку с начала массива до первого найденного \0
. Таким образом, t
не сохраняется, потому что он приходит после первого \0
.
Ответ 2
Поскольку конструктор std::string
, который принимает const char*
, рассматривает свой аргумент как строку стиля C. Он просто копирует его, пока он не попадет в нуль-терминатор, а затем прекратит копирование.
Таким образом, ваш последний пример действительно вызывает поведение undefined; word2[6]
проходит мимо конца строки.
Ответ 3
Вы создаете строку из char*
(или что-то, что затухает). Это означает, что применяется соглашение для C-строк. То есть они '\0'
завершены. Поэтому word2
содержит только "hello"
.
Ответ 4
Проблема в том, что вы вообще не печатаете строки - вы печатаете одиночные символы.
char word [] = "hello\0there";//Array of char...
cout << word[6] << endl; //So word[6] is the char't' (NOT a string)
string word2 = "hello\0there"; //std::string...
cout << word2[6] << endl; //so word2[6] is the char 't' (NOT a string as well)
Итак, вы вызываете перегрузки "char", а не "char *" или "строковые" перегрузки вообще, а символы NULL не имеют к этому никакого отношения: вы просто печатаете 6-й символ слова и 6-й символ слова2.
Если я правильно читаю ваши намерения, ваш тест должен выглядеть следующим образом:
cout << &(word[6]) (char*, should print "there")
cout << &(word2[6]) (char* as well, undefined behaviour pre-C++11)
В С++ 11 и более поздних версиях также будет напечатано "there" И будет четко определено