正如其他人所说,问题是存储到数组中的内存位置:x[i][j]。以下是一些原因:
你有一个二维数组,但是计算机的内存本质上是一维的。所以当你想象你的数组是这样的:
0,0 | 0,1 | 0,2 | 0,3
----+-----+-----+----
1,0 | 1,1 | 1,2 | 1,3
----+-----+-----+----
2,0 | 2,1 | 2,2 | 2,3
你的电脑将它以一行的形式存储在内存中:
0,0 | 0,1 | 0,2 | 0,3 | 1,0 | 1,1 | 1,2 | 1,3 | 2,0 | 2,1 | 2,2 | 2,3
在第二个例子中,你通过循环第2个数字来访问数组,即:
x[0][0]
x[0][1]
x[0][2]
x[0][3]
x[1][0] etc...
也就是说你是按顺序打的。现在看看第一个版本。你在做什么:
x[0][0]
x[1][0]
x[2][0]
x[0][1]
x[1][1] etc...
由于C语言在内存中布局二维数组的方式,你要求它在所有地方跳跃。但现在最重要的是:为什么这很重要?所有的内存访问都是一样的,对吧?
不:因为缓存。来自内存的数据以小块(称为“缓存线”)传输到CPU,通常为64字节。如果你有4字节的整数,这意味着你在一个整洁的小捆中得到16个连续的整数。取回这些内存块实际上是相当慢的;你的CPU可以在加载一条缓存线的时间内完成很多工作。
现在回头看看访问的顺序:第二个例子是(1)获取一个16个整数的块,(2)修改所有它们,(3)重复4000*4000/16次。这很好很快,而且CPU总有事情要做。
第一个例子是(1)抓取16个整数的块,(2)只修改其中一个,(3)重复4000*4000次。这将需要从内存中取回16倍的次数。你的CPU实际上不得不花时间坐在那里等待内存出现,而当它坐在那里的时候,你是在浪费宝贵的时间。
重要提示:
现在你有了答案,这里有一个有趣的注意:没有内在的原因,你的第二个例子必须是最快的一个。例如,在Fortran中,第一个例子是快的,第二个例子是慢的。这是因为,Fortran不像C语言那样将内容展开为概念上的“行”,而是展开为“列”,即:
0,0 | 1,0 | 2,0 | 0,1 | 1,1 | 2,1 | 0,2 | 1,2 | 2,2 | 0,3 | 1,3 | 2,3
C语言的布局被称为“行-主布局”,Fortran的布局被称为“列-主布局”。正如您所看到的,知道您的编程语言是行为主还是列为主是非常重要的!这里有更多信息的链接:http://en.wikipedia.org/wiki/Row-major_order