在C ++中,这是顺序访问2D数组的方式(内存块方式)

时间:2009-05-21 00:56:03

标签: c++ arrays

编辑:我从问题标题中删除了更快/更高效,因为它有误导性..我的意图不是优化而是理解数组。对不起,对不起!

int array[10][10], i, j;

for(i=0;i<10;i++)
{
    for(j=0;j<10;j++)
        std::cin>>array[i][j];
}

对战

int array[10][10], i, j;

for(i=0;i<10;i++)
{
    for(j=0;j<10;j++)
        std::cin>>array[j][i];
}

我很确定答案与如何在硬件级别实现数组有关; [] []语法只是程序员的抽象,以帮助可视化/建模。但是,我忘记了上面的代码从开始到结束依次访问内存块......

感谢所有答案......

只是为了确认我的理解,这是否意味着第一个代码相当于

int array[10][10], k;

for(k=0;k<100;k++)
{
    std::cin>>*(array+k);
}

6 个答案:

答案 0 :(得分:14)

除了等待获取用户输入将比阵列访问慢得多的事实之外,第一个更快。

如果您想了解有关该主题的更多背景信息,请查看this page on 2D array memory layout

使用第二个,您正在检查A[0], A[10] ... A[1], A[11].

第一个是顺序A[0], A[1], A[2] ..

答案 1 :(得分:6)

第一个具有更好的空间局部性。因为第一个下标是子数组的索引,第二个下标是该子数组中的元素;因此,当您修复i并改变j时,您正在查看所有在子阵列中的元素,因此它们是紧密相连的;但是当你修复j并改变i时,你会看到10个(子阵列的长度)分开的元素,因此非常分散。

答案 2 :(得分:3)

我同意这是不成熟的优化,但是......

C ++以行主要顺序存储矩阵。这将导致第一种语法更快(在大多数硬件上),因为您在内存中按顺序访问数组,并保留数据访问中的位置。

有关阵列存储的详细信息,请see this article

答案 3 :(得分:1)

在C ++中迭代数组的正确方法是第一种方法。像在第二个示例中所做的那样迭代一个“从外到内”的数组往往会更慢,因为在内部循环的每次迭代中,您将获得大不相同的内存位置。数组按顺序排列,第一种方法按内部行迭代。这为代码提供了有效使用CPU缓存的最佳机会,通过一次将一行加载到缓存中而不需要一直无效。

答案 4 :(得分:1)

对于小阵列来说,它不可能有任何区别!

但是对于较大的数组,第一个选项会更快,因为它将在序列中访问整个数组,因为它实际存储在内存中。此外,这将允许优化编译器访问整个技巧,以进一步加快速度。

对于阵列的每一次传递,第二个选项会弹回整个内存,这会降低缓存命中率,在最坏的情况下会涉及到大量的I / O分页虚拟内存的开启和关闭。

答案 5 :(得分:0)

您始终希望根据位置访问组中的内存位置,因此请先选择。 地方将在三个不同的层面发挥作用:

  1. 处理器缓存。您希望一起访问属于同一缓存行的内存位置。读取第一个元素需要缓存未命中读取命中,但后续的2-3个读取属于已缓存的内容。
  2. 翻译旁视缓冲区。您希望访问同一页面中的位置(通常为4k),以便虚拟到物理转换已经在处理器tlb中
  3. 虚拟页面。您希望访问同一页面上的位置,以便页面保留在流程工作集中,而不是移动到备用列表或甚至被换出
  4. 从处理器到处理器以及从操作系统到操作系统,情况各不相同,但只有很小的利润,除非你在谈论一些奇特的平台。