Неужели отправка символьного указателя - инициализированного в '\ 0' - к стандартному выводу не является ошибкой? (C ++) - PullRequest
4 голосов
/ 29 марта 2012

Это тривиально, возможно, глупо, но мне нужно понять, в каком состоянии cout остается после того, как вы попытаетесь распечатать содержимое указателя символа, инициализированного в '\ 0' (или 0). Взгляните на следующий фрагмент:

const char* str;
str = 0; // or str = '\0';
cout << str << endl;
cout << "Welcome" << endl;

В приведенном выше фрагменте кода строка 4 не будет выводить «Welcome» на консоль после попытки печати str в строке 3. Следует ли мне знать о каком-либо поведении? Если я заменю строку 1-3 на cout << '\ 0' << endl; </strong>, сообщение «Welcome» в следующей строке будет успешно выведено на консоль.

ПРИМЕЧАНИЕ. Строка 4 просто молча не печатается. Нет предупреждений, сообщений об ошибках или чего-либо еще (по крайней мере, без использования компилятора MinGW (g ++)). Это произвело исключение, когда я скомпилировал тот же код, используя компилятор MS cl.

РЕДАКТИРОВАТЬ: Чтобы рассеять представление о том, что код не работает, только когда вы присваиваете str для '\ 0', я изменил код, чтобы присвоить 0 - что ранее было прокомментировано

Ответы [ 5 ]

12 голосов
/ 29 марта 2012

Если вы вставляете значение const char* в стандартный поток (basic_ostream<>), требуется , чтобы оно не было нулевым. Поскольку str равно нулю, вы нарушаете это требование и поведение не определено.

Соответствующий параграф в стандарте находится в § 27.7.3.6.4 / 3.

Причина, по которой он работает с '\0' напрямую, заключается в том, что '\0' является char, поэтому никакие требования не нарушаются. Тем не менее, Potatoswatter убедил меня, что печать этого символа фактически определяется реализацией , поэтому то, что вы видите, может быть не совсем тем, что вы хотите (то есть выполнять свои собственные проверки!).

7 голосов
/ 29 марта 2012

Не используйте '\0', когда рассматриваемое значение не является "символом" (терминатор для строки с нулевым символом в конце или другой). То есть, я думаю, источник вашего замешательства. Что-то вроде:

char const* str = "\0";
std::cout << str << std::endl;

хорошо, где str указывает на строку, которая содержит '\0' (в этом дело, два '\0'). Что-то вроде:

char const* str = NULL;
std::cout << str << std::endl;

- неопределенное поведение; все может случиться.

По историческим причинам (начиная с C), '\0' и 0 преобразуют неявно для любого типа указателя, что приводит к нулевому указателю.

3 голосов
/ 29 марта 2012

A char*, что указывает на нулевой символ - это просто строка нулевой длины.Ничего страшного в этом нет.

Но char*, значение которого равно нулю - это отдельная история.Попытка распечатать это будет означать разыменование нулевого указателя, что является неопределенным поведением.Вероятен сбой.

Присвоение '\0' указателю, кстати, не совсем правильно, даже если это работает: вы назначаете символьное значение переменной указателя.Используйте 0 или NULL, или nullptr в C ++ 11 при назначении указателя.

3 голосов
/ 29 марта 2012

Только что касается cout << '\0' части ...

«Завершение строки» файла или потока в текстовом режиме не влияет на его содержимое. Стандарт C ++ относится к стандарту C по вопросам семантики текста (C ++ 11 27.9.1.1/2), а C довольно драконов (C99 §7.19.2 / 2):

Данные, считанные из текстового потока, будут обязательно сравниваться с данными, ранее записанными в этот поток, только если: данные состоят только из печатных символов и управляющих символов: горизонтальная табуляция и новая строка; символу новой строки не предшествует пробел; и последний символ - символ новой строки.

Поскольку '\0' является управляющим символом, а cout - текстовым потоком, результирующий вывод может не читаться так, как вы его написали.

1 голос
/ 29 марта 2012

Взгляните на этот пример: http://ideone.com/8MHGH

Основная проблема, с которой вы столкнулись, заключается в том, что str - это указатель на символ, а не символ, поэтому вам следует присвоить его строке: str = "\0";

Когда вы присваиваете ему значение char, оно остается равным 0, а затем бит сбоя cout становится истинным, и вы больше не можете печатать на нем.Вот еще один пример, где это исправлено: http://ideone.com/c4LPh

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...