-1

看起来像一个非常愚蠢的问题:这是声明数组指针的方式:

double * y = new double[26];

在这个声明之后,我在程序运行时观察了 y,这是我所看到的:

name    value
y[224] 8.691694942331e-310#DEN
y[225] CXX0030: Error: Expression cannot be evaluated

所以我想知道为什么声明为 26 长度的双精度数组有 224 个元素?谢谢。

编辑:但我试过这段代码,它通过了!

int nPt = 26;
double * y = new double[nPt];
y[224] = 0;

如果没有 y[224],它的值怎么可能被赋值?

4

4 回答 4

5

你的数组只有 26 个元素,你已经超出了它的范围。那是未定义的行为。该程序不必崩溃,它只是意味着任何事情都可能发生。这是一件坏事,必须避免。

于 2013-03-13T19:13:31.580 回答
5

当您分配内存时,使用new double[26],系统将为您的应用程序提供一块内存,其空间至少为 26 x sizeof(double)。分配函数确实会将数字 26(或可以以其他方式取回数字 26 的东西)存储在它的元数据内的某个位置,用于内存分配。

但是,调试器无法“弄清楚”元素的数量是 26,它只知道这是指向某些double值的指针。当您要求看起来超过 26 岁时,您就处于“未定义行为”领域——任何事情都可能发生并且可能会发生。包括它看起来像您“预期”的那样完美(也就是说,内存是可读的并且包含可以显示为“double”的值。然后,当您到达元素 224 时,调试器无法读取任何内存更长的时间(因为操作系统已将其标记为“不可用”)。那是它停止的时间。它可能是 50000000 [在这种情况下,您可能需要几个小时才能到达这里并提出这个问题......]

对。为简单起见,假设我们有一台具有 100KB RAM 的计算机。处理器分配用于什么目的的内存的方式是一次 4KB 的页面。所以我们有 25 页。其中一些页面是您的“堆”(其中new得到它的记忆)。一个内存分配获得了这样一个 4KB 页面的一部分。假设我们的内存恰好位于第 18 - 18 * 4096 = 73728 到 77823 页。第 19 页被标记为“未使用”。我们在这个页面中的分配是 168 字节(前 168 字节用于其他用途) - 所以我们的地址是 73896,现在,我们有 26 * 8 = 208 字节,所以“下一个可用字节”是 73728+376 = 74104这页纸。所以,y[0] 的地址是 73896,我们每个 double 占用 8 个字节。当我们到达 74104(索引 26,在我们分配的内存之外)时,我们仍然在第 18 页,根据处理器/操作系统,它仍然“可用”。在处理器说“你不能去那里”之前,我们必须一直走到 77824。74104 - 77824 = 3720 字节,或 465* sizeof(double)。但是我们正在使用我们被告知不要使用的内存。所以,

我希望这可以很好地解释它。

它是 4KB 的原因是,如果处理器必须跟踪内存的每一个字节,那么它会占用太多内存来跟踪该字节是否可用。4KB 是“我们检测到何时外出足够长的时间”和“它占用了太多容量”之间的一个很好的折衷。

于 2013-03-13T19:21:58.037 回答
4

所以我想知道为什么声明为 26 长度的双精度数组有 224 个元素?

它没有。您的调试器似乎无法确定y只有 26 个元素。

但是我尝试了这段代码,它通过了!

int nPt = 26;
double * y = new double[nPt];
y[224] = 0;

代码具有未定义的行为。这并不意味着它必须崩溃。以任何它喜欢的方式失败(或不失败)都是自由的。

于 2013-03-13T19:13:52.597 回答
0

C/C++ 中不存在数组。事实上,像 t[i] 这样的表达式只是表示我想访问地址 t 之外的第 i 个内存位置的捷径(一种语法糖)。当您分配一个大小为 N (new int[N]) 的内存块时,系统会为您提供一个地址,从该地址可以安全地从返回的地址访问 N 个内存位置(请注意,当我说 N 个内存位置时,它不是 N 个字节,而是 N*sizeof_one_element_in_bytes)。但是 C/C++ 允许您计算从返回的地址派生的任何地址,这取决于您确保不会访问错误的地址。C/C++ 运行时对数组大小一无所知,它无法保护您免受此类错误的影响。C/C++ 指针非常容易出错,您必须非常小心地使用它。这是接近机器和/或高效的代价。

于 2013-03-13T22:32:02.123 回答