#include<bits/stdc++.h>
using namespace std;
int arr[10][2];
int main(){
memset(arr,-1,sizeof(arr));
for(int i=0;i<10;i++)
cout<<arr[i][i]<<" ";
return 0;
}
result = -1 -1 -1 -1 -1 -1 -1 0 0 0
我声明了一个大小为2*10的数组作为全局变量,并使用memset函数将其初始化为-1。然而,当我在使用for语句时接近arr[I][I]这样的索引时,这个结果是如何得出的?
问题。
- 怎么会有arr[3][3],arr[4][4]的值。。。没有申报
- 为什么arr[7][7]、arr[8][8]、arr[9][9]的值与以前的值不同
谢谢。
您的程序有未定义的行为,因为您正在访问数组arr
边界之外的元素。
当你写道:
int arr[10][2]; //arr is a 2D array
上面的语句定义了一个2D数组。这意味着,arr
具有10
元素,并且这些10
元素中的每一个本身是2
int
元素的阵列。
这也意味着你只能(安全地(访问元素:
arr[0][0] arr[0][1]
arr[1][0] arr[1][1]
arr[2][0] arr[2][1]
...
...
arr[9][0] arr[9][1]
如果你试图(在for循环内部的程序中(访问上述界限之外的任何其他元素,你会得到未定义的行为。
未定义的行为意味着任何1都可能发生,包括但不限于提供预期输出的程序。但是永远不要依赖(或根据未定义行为的程序的输出得出结论(。
所以您看到的输出(可能看到的(是未定义行为的结果。正如我所说,不要依赖于有UB的程序的输出。
因此,使程序正确的第一步是删除UB(在这种情况下,通过确保索引不会超出界限(然后并且只有到那时您才能开始对程序的输出进行推理。
解决方案1
一种替代方案是使用std::vector
,如下所示:
//create a 2D vector with 10 rows and 2 columns where each int element has value -1
std::vector<std::vector<int>> arr(10, std::vector<int>(2, -1));
溶液2
您应该考虑使用std::fill
而不是memset
:
std::fill(*arr, *arr + 10*2, -1);
1对于未定义行为的更准确的技术定义,请参阅此处,其中提到:对程序的行为没有限制
当你清楚地时,答案很简单
- 数组是内存中保存连续内存区域的对象
2D
阵列类似于1D阵列的1D
阵列,每一个下一行都放在存储器中前一行的旁边- 数组的名称是对内存区域的引用
- 数组类型(这个值的大小(是编译器知道每个元素占用多少字节的方式
cpp
不检查元素大小,您可以自由使用任何索引,这只是为了检索内存中数组旁边的不可预测值
例如,您有byte arr[3][2]
,这意味着我们定义了一个包含int
元素的数组,其中3
行,每行2
列。
sizeof(byte) = 1
-数组中的每个元素都占用1
字节,这就是内存的分配方式。
0xA 0xB 0xC 0xD 0xE 0xF 0xAA 0xBB 0xCC
(前6个字节是数组;列表3个字节-是内存中的另一个数据;arr
是指向第一个元素的指针(
memset(arr,0,sizeof(arr))
-清除或初始化数组;内存将是这样的:
0x0 0x0 0x0 0x0 0x0 0x0 0xAA 0xBB 0xCC
arr[1][0] = 3
—将一个元素设置为1
;内存将是这样的:
0x0 0x0 0x3 0x0 0x0 0x0 0xAA 0xBB 0xCC
那么你会如何解读这个元素:
arr[1][0]; // 3
*(arr + sizeof(byte) * 2); // 3
正如你所看到的,你可以很容易地阅读smth。在阵列后面并得到不可预测的结果:
arr[3][0]; // 0xAA
*(arr + sizeof(byte) * 7); // 0xBB
p。S.我描述了为什么会得到这个结果的一般答案。我不想在另一个方面强调旋转,因为根据CPU寻址规则,其中byte
可以占用内存中的4
字节,但不会使用最后的3
字节(