在 'for (auto c : str)' 中,c 到底是什么?

In 'for (auto c : str)' what exactly is c?

如果我声明:

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 究竟是什么?

for (auto& c : s) 

c 是一个 reference 到一个字符 (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])

In 'for (auto c : str)' what exactly is c?

c是在range-for语句范围内自动存储的局部变量。它的类型将被推导出来,因为你使用了 auto。在 string str="ARZ"; 的情况下,推导的类型将为 char.

Presumably c is just a pointer into the vector

没有向量,c也不是指针。这是一个 char.

了解 range-for 的作用可能会有所帮助。它等效于执行以下操作(程序员无法访问 __ 前缀变量;它们是循环行为的概念):

{
    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 将被推断为对char 的引用。将 addressof 运算符应用于引用不会生成引用变量的地址,而是生成引用对象的地址。在这种情况下,引用的对象将是字符串中的字符。

在此基于范围的for循环

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

因为字符串 s 的大小等于 3.

,所以有 3 次迭代

在循环中,对象 c 的赋值被忽略,对象由字符 '?' 重新赋值。所以输出三个字符'?'.

局部变量c的类型是char即classstd::string

的值类型

在此基于范围的for循环

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

变量 c 有一个引用类型,更准确地说是 char & 类型。所以在这个循环中输出引用对象的地址。即在这个循环中输出字符串s的元素地址。

在此基于范围的for循环

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

输出同一个局部变量的地址c.

当您使用引用时,引用 c 是对字符串中某个字符的引用。

当您不使用引用时,c 是一个普通的 char 变量,其中包含字符串中字符的 copy

非引用变体为所有迭代提供相同指针的原因只是一个实现细节,其中编译器在每次迭代中为变量 c 重用 space。

In 'for (auto c : str)' what exactly is 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 生命周期开始之前结束,因此它会在同一位置分配并获得相同的地址。你不能依赖那个。

如果不知道类型,可以让编译器告诉你:

#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& ... 循环。

cchar

语法可能会产生误导,直到您真正理解它(但它是有道理的)。

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

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

简写:需要修改内容时使用auto&