В 'for (auto c: str)' что такое c? - PullRequest
       25

В 'for (auto c: str)' что такое c?

2 голосов
/ 26 сентября 2019

Если я объявлю:

string s = "ARZ";

, а затем запустите следующий код:

for (auto& c : s) {
  cout << (void*)&c << endl;
}

результаты будут соответствовать адресам s[0], s[1] и s[2] соответственно.

Если я удаляю & и запускаю:

for (auto c : s) {
  cout << (void*)&c << endl;
}

, адрес c всегда одинаков.

Предположительно c - это просто указатель на вектор, и его значение увеличивается на sizeof(char) с каждым циклом, но мне трудно понять, почему мне не нужно писать *c для доступа к строковым значениям char.

И, наконец, если я бегу:

for (auto c: s) {
  c='?';
  cout << c << endl;
}

Он выводит 3 знака вопроса.

Мне трудно понять, что на самом деле является c?1030 *

Ответы [ 7 ]

7 голосов
/ 26 сентября 2019

В 'for (auto c: str)' что именно есть c?

Это локальная переменная, область действия которой составляет весь блок for и имеет тип char.

for (auto c : str) { loop_statement }

эквивалентно

{
    for (auto __begin = str.begin(), __end = str.end(); __begin != __end; ++__begin) {
        auto c = *__begin;
        loop_statement
    }
}

В некоторых реализациях при некоторых условиях, поскольку время жизни c заканчивается до того, как начинается время жизни c следующей итерации, онополучает в том же месте и получает тот же адрес.Вы не можете полагаться на это.

6 голосов
/ 26 сентября 2019

Если вы не знаете тип, вы можете позволить компилятору сообщить вам:

#include <string>

template <typename T>
struct tell_type;


int main(){
    std::string s = "asdf";
    for (auto& c : s) { 
        tell_type<decltype(c)>();
    }
}

Обратите внимание, что для tell_type нет определения, следовательно, это приведет к ошибке в строкеиз:

error: implicit instantiation of undefined template 'tell_type<char>'

И аналогично

error: implicit instantiation of undefined template 'tell_type<char &>'

для петли for (auto& ....

2 голосов
/ 26 сентября 2019

c - это char.

Синтаксис может вводить в заблуждение, пока вы не подпишете его (но это имеет смысл).

for (auto c : s) //*distinct object* (think: a copy usually)

for (auto& c : s) //reference into the string (can modify string)

Short: используйте auto&, когда вам нужно изменить содержимое.

2 голосов
/ 26 сентября 2019

В 'for (auto c : str)' что такое c?

c - локальная переменная с автоматическим хранением в области действия оператора range-for.Его тип будет выведен, потому что вы использовали auto.В случае string str="ARZ"; выводимый тип будет char.

Предположительно, c - это просто указатель на вектор

Нет вектора, а cне указательЭто char.

Понимание того, что делает диапазон, может помочь.Это эквивалентно следующему (__ переменные с префиксом недоступны для программиста; они являются концептуальными для поведения цикла):

{
    auto && __range = range_expression;
    auto __begin = begin_expr;
    auto __end = end_expr;
    for (; __begin != __end; ++__begin) {
        range_declaration = *__begin;
        loop_statement
    }
} 

Или, в данном конкретном случае:

{
    auto && __range = str;
    auto __begin = range.begin();
    auto __end = range.end();
    for ( ; __begin != __end; ++__begin) {
        auto c = *__begin;         // note here
        cout << (void*)&c << endl;
    }
}

Обратите внимание, что если вы используете auto&, то c будет выводиться как ссылка на символ.Применение оператора addressof к ссылке приведет не к получению адреса ссылочной переменной, а к адресу ссылочного объекта.В этом случае указанный объект будет символом в строке.

1 голос
/ 26 сентября 2019

Когда вы используете ссылки, ссылка c является ссылкой на символ внутри строки.

Если вы не используете ссылки, c - это простая переменная char, которая содержит копия символа в строке.

Причина, по которой вариант без ссылки дает один и тот же указатель для всех итераций, - просто деталь реализации, где компилятор повторно использует пространство для переменнойc внутри каждой итерации.

1 голос
/ 26 сентября 2019

В этом цикле на основе диапазона для

for (auto c: s) {c='?'; cout << c << endl;}

существует три итерации, поскольку размер строки s равен 3.

В цикле назначенныйзначение объекта c игнорируется, и объект переназначается символом '?'.Таким образом, выводятся три символа '?'.

Тип локальной переменной c равен char, что является типом значения класса std::string

В этом цикле на основе диапазона for

for (auto& c : s) cout << (void*)&c << endl;

переменная c имеет ссылочный тип, точнее тип char &.Таким образом, в этом цикле выводятся адреса ссылочных объектов.То есть в этом цикле выводятся адреса элементов строки s.

В этом основанном на диапазоне для цикла

for (auto c : s) cout << (void*)&c << endl;

выводится адрес той же локальной переменнойc.

0 голосов
/ 26 сентября 2019
for (auto& c : s) 

c - это ссылка на символ (char&)

Этот цикл примерно эквивалентен C:

for (char* c=str; *c; ++c)

for (auto c : s)

c - это символ (char)

Этот цикл примерно эквивалентен C:

int i=0;
for (char c=str[i]; i<strlen(str); c=str[++i])

...