C ++: вывод указателей смущает меня - PullRequest
1 голос
/ 01 февраля 2012

Итак, у меня есть следующий код:

    cout << _userLoginName << endl;
    cout << *_userLoginName << endl;
    cout << (_userLoginName+1) << endl;
    cout << *(_userLoginName+1) << endl;

переменная char * _userLoginName была установлена ​​равной "smith". Мой вопрос прост: почему в последних строках кода я получаю следующий вывод?

smith // as from cout << _userLoginName << endl;
s // as from cout << *_userLoginName << endl;
mith // cout << (_userLoginName+1) << endl;
m // cout << *(_userLoginName+1) << endl;

Я действительно пытался обосновать результат, но не могу понять. Спасибо.

Ответы [ 6 ]

3 голосов
/ 01 февраля 2012

Если вы дадите cout 1 a char *, он попытается напечатать строку. Если вы дадите ему char, то он напечатает этот единственный символ.

_userLoginName и (_userLoginName+1) относятся к типу char *; *_userLoginName и *(_userLoginName+1) относятся к типу char.


1. Технически, «дай std::operator<<(std::ostream &, T)».

2 голосов
/ 01 февраля 2012

Вытащите лист бумаги и нарисуйте коробку с шестью ячейками с надписью «кузнец»:

+-+-+-+-+-+--+
|s|m|i|t|h|\0|
+-+-+-+-+-+--+
 ^ ^
 | +- _userLoginName + 1
 +- _userLoginName

Используйте перо в качестве указателя «_userLoginName» и наведите его на первую ячейку.Разыменование указателя (т. Е. Использование *ptr для указателя ptr) означает просмотр содержимого ячейки, на которую он указывает.То есть '* _userLoginName' отображается в содержимом ячейки.Написание указателя типа char* или char const* делает нечто забавное: он следует за указателем и записывает содержимое каждой найденной ячейки, пока не достигнет ячейки со значением \0.

Это должно объяснитьпервыми на выходы.Теперь ptr + 1 смотрит на ячейку рядом с ptr, т. Е. ptr + 1 - это другой указатель (при необходимости вытащите другое перо), помещающий следующую ячейку.Он делает то же самое, что и выше.

0 голосов
/ 01 февраля 2012

Здесь работают две отдельные перегрузки для operator<<: одна для указателей на символы и одна для символов.Второй для отдельных символов просто печатает этот символ.Первый, для указателей на символы, обрабатывает указатель как указатель на первый символ в массиве символов с нулевым символом в конце («строка») и печатает все эти символы.

Объедините это с синтаксисом языка, которыйa[i] совпадает с *(a + i) для массива a, и у вас есть:

cout << s;      // prints all characters, starting at the first
cout << *s;     // prints only the first character, equal to "cout << s[0];"
cout << s + 1;  // prints all  characters, starting at the second
cout << *(s+1); // prints only the second character, equal to "cout << s[1];"
0 голосов
/ 01 февраля 2012

Первый cout смотрит на указатель userLoginName (char * и char [] очень схожи в c ++).cout будет печатать все значения в памяти, обрабатывая их как символы, пока не встретит символ '\0', который завершает строку.

Второй cout просматривает один элемент памяти, которыйуказывает userLoginName или userLoginName[0].

Третий cout делает то же самое, что и первый, но адрес памяти начинается на 1 символ позже, чем userLoginName, так как указатель имеет тип char.

Последний кут такой же, как второй, но userLoginName[1].

0 голосов
/ 01 февраля 2012

Разыменование указателя (например, *_userLoginName) всегда возвращает элемент, на который указывает указатель, в случае нормальной строки первый символ в нем, который затем печатается.

Добавление n к указателю (например, _userLoginName+1) увеличивает указатель на n шагов, поэтому, если он указывает на 0-й элемент, он впоследствии будет указывать на n-й элемент.

Объедините два, чтобы объяснить четвертую строку.

0 голосов
/ 01 февраля 2012

Рассмотрим тип *_userLoginName - это char.

Может быть, вы упустили из виду, что * в этом контексте разыменовывает указатель?

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