我有以下几点:
#include <stdio.h>
int main() {
int a[2][2] = { 0,1,2,3};
printf("\n%d %d \n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);
return 0;
}
返回:
0 1
2 3
0 2 0 1491303602
有没有办法访问索引为1的二维数组?因为数组保存在连续的内存中,难道我们不能这样做吗?
同时:
printf("\n%d %d \n%d %d\n",&a[0][0],&a[0][1],&a[1][0],&a[1][1]);
printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);
生成以下内容:
1137924528 1137924532
1137924536 1137924540
1137924528 1137924536 1137924544 1137924552
那么,为什么前两个元素的内存地址&a[0][0] = a[0]和&a[0][1] = a[1],而后两个元素的内存地址不匹配呢?
3条答案
按热度按时间58wvjzkj1#
在代码段中
该线路
相当于:
这意味着您访问的对象
a
超出了界限,这将调用undefined behavior。您可能需要执行以下操作:
另一种写法是这样的:
这些程序在我的编译器上有以下输出:
虽然这可能在所有编译器上都有效,但值得注意的是,这样做可能会调用未定义的行为,这取决于您对标准的解释有多严格。这是因为您访问的是第一个超出界限的子数组
a[0]
,而不是整个对象a
。请参阅以下问题以了解更多信息:One-dimensional access to a multidimensional array: is it well-defined behaviour?
如果我用
-fsanitize=undefined
编译,编译器gcc和clang实际上都为第二个程序提供了一个运行时警告。如果我启用所有警告,编译器clang还提供了一个编译时警告。基于这些原因,如果你想将一维数组作为二维数组使用,最好声明一个一维数组而不是二维数组,并且自己对一维数组执行索引计算。这样,你就可以确定你所做的是ISO C标准允许的。下面是一个例子:
此程序具有以下输出:
那么,为什么前两个元素的内存地址&a[0][0] = a[0]和&a[0][1] = a[1],而后两个元素的内存地址不匹配呢?
数组
a
由2个子数组组成,每个子数组由2个int
元素组成,因此int
元素的总数为4。在你的问题中,地址如下:
1137924528
是元素a[0][0]
的地址。1137924532
是元素a[0][1]
的地址。1137924536
是元素a[1][0]
的地址。1137924540
是元素a[1][1]
的地址。在你的问题中,
具有以下输出:
最后两个地址超出界限,因为子数组
a[2]
和a[3]
不存在。只存在a[0]
和a[1]
。如果
a[2]
确实存在,其地址将是1137924544
,这将是二维数组的第5个int
元素的地址,即a[0][4]
(因为C中的索引是从0开始的)。但是,我怀疑这些地址实际上是否正确,因为您在打印地址时使用了错误的
printf
说明符。为了打印地址,您应该使用%p
而不是%d
,因为%d
用于int
,不是指针。在指针为64位而int
为32位的平台上,32个最高有效位可能会从值中剥离,甚至更糟。oogrdqng2#
https://godbolt.org/z/3avvnssn5
结果:
f87krz0w3#
让我们“绘制”您的数组:
由此不难看出一种模式,它告诉我们可以使用单个数组来表示所有两个“维度”:
现在我们要做的就是给出一个公式,从矩阵x,y对中计算出一个数组的索引。
在第一个“行”中,我们通过简单地使用列索引来获得索引。对于第二个“行”,我们需要添加“列”的数量。
因此,一般计算为
current_row * total_columns + current_column
。我将其编码如下: