如何在C++中访问索引数组


#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]这样的索引时,这个结果是如何得出的?

问题。

  1. 怎么会有arr[3][3],arr[4][4]的值。。。没有申报
  2. 为什么arr[7][7]、arr[8][8]、arr[9][9]的值与以前的值不同

谢谢。

您的程序有未定义的行为,因为您正在访问数组arr边界之外的元素。

当你写道:

int arr[10][2]; //arr is a 2D array

上面的语句定义了一个2D数组。这意味着,arr具有10元素,并且这些10元素中的每一个本身是2int元素的阵列。

这也意味着你只能(安全地(访问元素:

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字节(

最新更新