- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是 C++ 的新手。
int*
?&
有什么用?.
int arr[10][3];
for (auto &i : arr)
{
for (auto j : i)
{
//sth
}
}
最佳答案
首先我们需要知道int arr[10][3];
的具体数据类型.它是一个由 10 个数组组成的 数组,每组 3 个 int
.
循环通常迭代多维容器的一个维度,例如
for(int i = 0; i < 10; ++i)
{
for(int j = 0; j < 3; ++j)
{
arr[i][j] = 0;
}
}
第一个循环遍历 10 的数组 X
,第二个循环然后遍历 X
,这是一个数组,包含 3 int
.
下一步是显式使用这个 X
在代码中:
for(int i = 0; i < 10; ++i)
{
int (&x)[3] = arr[i]; // you won't see this syntax often
for(int j = 0; j < 3; ++j)
{
int &elem = x[j];
elem = 0;
}
}
行int (&x)[3]
声明对 数组 3 int
的引用,这是访问多维数组第一层arr
的结果.
我们也可以使用迭代器来写这个例子:
for(int (*px)[3] = arr; px != arr+10; ++px)
{
// `px` is a _pointer to an array of 3 `int`_
// `*px` then is an _array of 3 `int`_
for(int *pelem = *px; pelem != (*px)+3; ++pelem)
{
*pelem = 0;
}
}
请注意,我在这里使用的功能是将数组转换为指向其第一个元素的指针。这称为衰减:一个数组是/可以衰减到一个指针(指向该数组的第一个元素),例如
int my_arr[3];
int *p = my_arr; // `p` now points to the first element of `my_arr`
p = &my_arr[0]; // equivalent
对于多维数组,这变成了
int arr[10][3];
int (*p)[3]; // a pointer to an _array of 3 `int`_
p = arr; // `p` now points to the first element of `arr`, i.e.
// the first _array of 3 `int`_
最后但同样重要的是,对于多维数组,也可以这样写:
for(int *pelem = arr[0]; pelem != arr[0]+10*3; ++pelem)
{
*pelem = 0;
}
但这只适用于多维数组,因为它们在内存中是连续布局的,并且多维数组的内存布局是指定的。
这对于像 vector<vector<int>>
这样的容器是不可能的, 尽管
vector<int> v = {1,2,3,4,5};
for(int* i = &v[0]; i != &v[0] + 5; ++i)
{
*i = 0;
}
格式正确,没有未定义的行为。
相同的逻辑现在适用于基于范围的 for 循环:
for(int (&x)[3] : arr)
{
for(int &elem : x)
{
elem = 0;
}
}
拥有基于范围的 for 循环的全部意义在于摆脱显式迭代器。 int*
就是这样一个迭代器,所以没有必要使用基于范围的 for 循环遍历 int*
海事组织。
how does this nested range-based for perform, deeply?
C++ 语言标准在 [stmt.ranged] 中定义了基于范围的 for 语句如下(注意我已经简化了一点):
for (
for-range-declaration:
expression)
statement
决议为:
{
for ( auto __begin = /*begin-expr*/,
__end = /*end-expr*/;
__begin != __end;
++__begin )
{
/*for-range-declaration*/ = *__begin;
/*statement*/
}
}
for-range-declaration 和 statement 本质上是从未解析的基于范围的 for 循环中复制粘贴的。其余的(begin-expr、end-expr)有些复杂,这里是一个简化版本:
{
using std::begin;
using std::end;
for ( auto __begin = begin(/*expression*/),
__end = end(/*expression*/);
__begin != __end;
++__begin )
{
/*for-range-declaration*/ = *__begin;
/*statement*/
}
}
我的基于范围的 for 循环示例是从
for(int (&x)[3] : arr)
{
/*statements*/
}
到
{
using std::begin;
using std::end;
for ( auto __begin = begin(arr),
__end = end(arr);
__begin != __end;
++__begin )
{
int (&x)[3] = *__begin;
/*statements*/
}
}
或者,通过解析 begin
/end
调用:
{
for ( int (*__begin)[3] = arr,
__end = arr + 10;
__begin != __end;
++__begin )
{
int (&x)[3] = *__begin; // (A)
/*statements*/
}
}
标有 (A)
的行还显示了为什么 &
在一个例子中 for (int x[3] : arr)
是必要的:
int arr[10][3];
int (&x)[3] = arr[0]; // well-formed
int x [3] = arr[0]; // ill-formed for arrays
不允许直接分配原始/C 风格的数组,您可能从类似的示例中了解到
int my_arr[10];
int my_sec_arr[10] = my_arr; // not legal, ill-formed
这就是您必须使用引用的原因。
使用标准库的 std::array
等其他容器,可以避免引用:
std::array<int, 10> my_arr;
std::array<int, 10> my_sec_arr = my_arr; // well-formed
但是赋值意味着复制,所以必须复制整个数组;而此处的引用不需要复制。
作为Yakk指出in the comments ,这并不是 &
的原因在你的例子中是必要的for (auto &i : arr)
, 作为 auto &i = arr[0];
解析为 int (*i)[3] = arr[0];
.但如您所见,auto
将数组衰减为指针,因此您的第二次迭代失败:
for(auto i : arr)
{
// type of `i` now is _pointer to an array of 3 `int`_
for(auto j : i) // can't iterate over a pointer: what are the boundaries?
{
/* ... */
}
}
更精确一点:您可以遍历一个数组,因为编译器知道数组中有多少个元素;它是类型的一部分,例如3 的数组 int
,并且类型是编译器已知的。
对于指针,编译器不知道指针是指向单个元素还是指向元素数组,在后一种情况下它不知道该数组有多大。任何情况下的类型都是,例如指向int
的指针:
int my_arr[10];
int my_int;
int *p;
p = my_arr;
p = &my_int;
p = new int[25];
关于c++ - 为什么在嵌套的基于范围的 for 循环中引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17907913/
我不能解决这个问题。和标题说的差不多…… 如果其他两个范围/列中有“否”,我如何获得范围或列的平均值? 换句话说,我想计算 A 列的平均值,并且我有两列询问是/否问题(B 列和 C 列)。我只希望 B
我知道 python 2to3 将所有 xrange 更改为 range 我没有发现任何问题。我的问题是关于它如何将 range(...) 更改为 list(range(...)) :它是愚蠢的,只是
我有一个 Primefaces JSF 项目,并且我的 Bean 注释有以下内容: @Named("reportTabBean") @SessionScoped public class Report
在 rails3 中,我在模型中制作了相同的范围。例如 class Common ?" , at) } end 我想将公共(public)范围拆分为 lib 中的模块。所以我试试这个。 module
我需要在另一个 View 范围 bean 中使用保存在 View 范围 bean 中的一些数据。 @ManagedBean @ViewScoped public class Attivita impl
为什么下面的代码输出4?谁能给我推荐一篇好文章来深入学习 javascript 范围。 这段代码返回4,但我不明白为什么? (function f(){ return f(); functio
我有一个与此结构类似的脚本 $(function(){ var someVariable; function doSomething(){ //here } $('#som
我刚刚开始学习 Jquery,但这些示例对我帮助不大...... 现在,以下代码发生的情况是,我有 4 个表单,我使用每个表单的链接在它们之间进行切换。但我不知道如何在第一个函数中获取变量“postO
为什么当我这样做时: function Dog(){ this.firstName = 'scrappy'; } Dog.firstName 未定义? 但是我可以这样做: Dog.firstNa
我想打印文本文件 text.txt 的选定部分,其中包含: tickme 1.1(no.3) lesson1-bases lesson2-advancedfurther para:using the
我正在编写一些 JavaScript 代码。我对这个关键字有点困惑。如何在 dataReceivedHandler 函数中访问 logger 变量? MyClass: { logger: nu
我有这个代码: Public Sub test() Dim Tgt As Range Set Tgt = Range("A1") End Sub 我想更改当前为“A1”的 Tgt 的引
我正忙于此工作,以为我会把它放在我们那里。 该数字必须是最多3个单位和最多5个小数位的数字,等等。 有效的 999.99999 99.9 9 0.99999 0 无效的 -0.1 999.123456
覆盖代码时: @Override public void open(ExecutionContext executionContext) { super.open(executio
我想使用 preg_match 来匹配数字 1 - 21。我如何使用 preg_match 来做到这一点?如果数字大于 21,我不想匹配任何东西。 example preg_match('([0-9]
根据docs range函数有四种形式: (range) 0 - 无穷大 (range end) 0 - 结束 (range start end)开始 - 结束 (range start end st
我知道有一个UISlider,但是有人已经制作了RangeSlider(用两个拇指吗?)或者知道如何扩展 uislider? 最佳答案 我认为你不能直接扩展 UISlider,你可能需要扩展 UICo
我正在尝试将范围转换为列表。 nums = [] for x in range (9000, 9004): nums.append(x) print nums 输出 [9000] [9
请注意:此问题是由于在运行我的修饰方法时使用了GraphQL解析器。这意味着this的范围为undefined。但是,该问题的基础知识对于装饰者遇到问题的任何人都是有用的。 这是我想使用的基本装饰器(
我正在尝试创建一个工具来从网页上抓取信息(是的,我有权限)。 到目前为止,我一直在使用 Node.js 结合 requests 和 Cheerio 来拉取页面,然后根据 CSS 选择器查找信息。我已经
我是一名优秀的程序员,十分优秀!