Цикл для строки не используется и в то время как тело цикла используется &

#include "iostream"

int main()
{
  std::string s = "abc";
  for ( const auto& item : s ) {
    std::cout << &item << std::endl;
  }
}

результат азбука До нашей эры с

#include "iostream"

int main()
{
  std::string s = "abc";
  for ( const auto item : s ) {
    std::cout << &item << std::endl;
  }
}

затем выведите странные слова, но первое слово правильное

в чем разница между двумя приведенными выше кодовыми блоками?

Вы знаете, что означает &?

HolyBlackCat 20.08.2023 16:50

@HolyBlackCat, это адрес персонажа в строке

jurkDang 20.08.2023 16:52

В первом случае вы печатаете указатель char*, указывающий на блок символов, управляемый s; этот блок символов завершается нулем. Во втором случае у вас есть временная переменная char, вы берете адрес этой переменной и обрабатываете его как указатель на строку с завершающим нулем, но это не так. Затем программа демонстрирует неопределенное поведение из-за переполнения буфера.

Igor Tandetnik 20.08.2023 16:58

А знаете ли вы, что происходит, когда вы передаете адрес символа в << выходного потока?

Sam Varshavchik 20.08.2023 16:58

Да, так что вы ожидаете, что он напечатает символ или адрес?

Pepijn Kramer 20.08.2023 16:59

@Pepijn Kramer, ожидайте, что будет напечатано то же самое с первым блоком

jurkDang 20.08.2023 17:02

Итак, даже если и const auto& item, и &item используют &, то & делает разные вещи. const auto& item устанавливает константную ссылку на элемент, и для остальной части кода она будет «выглядеть» как этот элемент. Во втором случае & возвращает адрес товара. Так что это может быть немного сложно выучить, но значение & зависит от контекста.

Pepijn Kramer 20.08.2023 17:08

@Sam Варшавчик, он будет печатать символы адреса и рядом с ним, пока не коснется nul-terminated

jurkDang 20.08.2023 17:16

Ага, а const auto item — персонаж-одиночка, рядом с ним ничего нет.

HolyBlackCat 20.08.2023 17:19

Во втором примере вы передаете адрес переменной item в operator<<, а не адрес чего-либо в строке. Это происходит только в первом примере.

john 20.08.2023 17:20

Правильно, так что именно в наблюдаемых результатах вам непонятно?

Sam Varshavchik 20.08.2023 17:34
static_cast<void const*>(&item) чтобы распечатать адрес товара. Предположим, что это ваше намерение.
Eljay 20.08.2023 17:51

@Sam Varshavchik , код второго блока item это копия персонажа , а не символ s , меня это смутило , теперь я понял

jurkDang 20.08.2023 17:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
13
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

& можно использовать для разных целей.

  • 0xF0 & 0x0F --> & побитовое и
  • true && false --> && - логическое/логическое и
  • int var{0}; &var; --> & является оператором адреса и возвращает адрес объекта или указатель на объект, на котором вы его используете.
  • int& sameVar{var}; --> & создает ссылку с именем sameVar, которая привязана к var. С его помощью вы можете получить доступ к var и изменить его, как если бы у вас был «настоящий» var.

Вы используете оператор адреса в каждом операторе std::cout, который возвращает char* (указатель на char). При печати чего-то вроде int* с std::cout он выводит свой адрес, который может выглядеть так: 000000734F9CF8D4. Однако char*s — это нечто особенное в языках C и C++, поскольку они используются для представления c-строк. std::cout будет печатать все следующие char, начиная с адреса памяти, который вы ему дали, пока не встретится с \0, который является ограничителем NUL для c-строк.


В первом блоке кода вы используете

for ( const auto& item : s )
// which is the same as
for ( const char& item : s)

// you could imagine the loop like this:
for (int i{ 0 }; i < s.size(); i++) {
    std::cout << &s[i] << std::endl;
}

Это означает, что каждый item ссылается на char в вашем std::string s. В первой итерации item == s[0] будет правдой, а также &item == &s[0] будет правдой. В следующих итерациях эти два утверждения по-прежнему будут истинными, если вы будете увеличивать индекс на каждой итерации. Это означает, что вы будете печатать c-строку на каждой итерации, но продвигаясь вперед к первой char, вы печатаете каждый раз. Поэтому вы получаете вывод:

abc
bc
c

Во втором блоке кода вы используете

for ( const auto item : s )
// which is the same as
for ( const char item : s)

// you could imagine the loop like this:
for (int i{ 0 }; i < s.size(); i++) {
    char copy{ s[i] };
    std::cout << &copy << std::endl;
}

Это означает, что каждый item сейчас является копией char в s. item == s[0] по-прежнему будет истинным, но &item == &s[0] не будет истинным, поскольку это разные объекты. То же самое касается следующих итераций и увеличения индекса. Поскольку вы на самом деле не знаете адрес item здесь и то, что следует за ним, вы не должны печатать его таким образом. Поскольку std::cout будет продолжать печатать char, пока не достигнет \0, вы получите случайный мусор.

Другие вопросы по теме