在 '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& ...
循环。
c
是 char
。
语法可能会产生误导,直到您真正理解它(但它是有道理的)。
for (auto c : s) //*distinct object* (think: a copy usually)
for (auto& c : s) //reference into the string (can modify string)
简写:需要修改内容时使用auto&
如果我声明:
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
.
在循环中,对象 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& ...
循环。
c
是 char
。
语法可能会产生误导,直到您真正理解它(但它是有道理的)。
for (auto c : s) //*distinct object* (think: a copy usually)
for (auto& c : s) //reference into the string (can modify string)
简写:需要修改内容时使用auto&