c - 为什么二维数组在将其中一行复制到以前未定义的位置时会发生变化?
问题描述
看下面的代码示例,我故意将 a[2] 复制到不存在的 p[2] (只有 p[1] 和 p[0] 存在)我猜这应该对数组 a 没有影响。
但是当我打印'r'引用的数组a时,输出如下
00
34
-133280
34
如果我要么完全删除
p[2]=a[2]
或更正这两个陈述
IE
p[0]=a[0]
p[1]=a[1]
然后错误消失了,我得到了预期的输出
这是审查的代码
int a[2][2]={{1,2},{3,4}};
int * p[2];
int (*r)[2];
p[1]=a[1];
p[2]=a[2]
r=a;
我期望的输出
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
printf("%d",p[i][j]);
printf("\n");
}
printf("NExt\n");
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
printf("%d",r[i][j]);
printf("\n");
}
成为
00
34
12
34
提前致谢
解决方案
首先,为什么你期望打印的结果p
是
00
34
有例外,但未初始化的内存不能保证一开始就包含 0。更重要的是,随机指针(p[0]
在您的情况下就是这种情况)尤其不能保证指向包含 0 的内存!我期望的结果是
meaningless pseudo-random numbers
34
其次,当您写入不属于您的内存时,例如
p[2] = a[2];
这是一件非常糟糕的事情,几乎任何事情都可能发生。
这里有两件事不会发生:
编译器检测到您正在写入不属于您的内存,并给您一条错误消息。
编译器检测到您正在写入不属于您的内存,并确保在任何地方都没有写入任何内容。
不,通常发生的情况是
- 尝试写入您不拥有的内存,结果非常糟糕。
你说,“我猜这应该对 array 没有影响a
。” 我不知道你为什么这么猜。我们有两个事实:
(a) 程序正在写入数组之外的某些内存部分p
。我们不知道它实际写在哪里;它几乎可以在任何地方。
(b) 数组a
被神秘地写入。
鉴于这两个事实,你能猜出糟糕的写作实际上可能在哪里写吗?
另请参阅此对不相关问题的答案,尤其是有关“如果有内存并且我们确实获得许可并且它没有被用于其他任何事情,则该程序似乎可以工作的段落 - 现在”。
附录:在评论中,您问“但是在连续编译中,被覆盖的内存不应该不同”。有两种方法可以回答这个问题。
作为 C 程序员(实际上是任何类型的程序员),了解当您从事未定义的行为时,任何事情都可能发生,这一点非常重要。让我重复一遍:任何事情都可能发生。让我再重复一遍:任何事情都有可能发生!结果不一定是合理的。他们不必说得通。它们不必局限于您可能预期会出错的事情。如果您认为它们是随机的,它们不必因运行而异。如果您认为它们是一致的,它们不必每次运行都保持不变。您根本无法对可能发生或可能不会发生的事情做出任何预测。最好的解决方案——唯一的解决方案——首先不要从事未定义的行为。
有时,未定义行为的结果令人惊讶。(几乎没有什么让我感到惊讶,但有时一些程序员会感到惊讶。)如果对编译器和目标体系结构有足够的了解,只要有足够的时间和精力,通常可以对观察到特定结果的原因做出令人满意的解释。但是由于我对您的编译器和目标架构一无所知,并且(对不起)我几乎没有时间回答这个问题,所以我不会推测为什么(在这种情况下)它们会导致和你预期的不一样。
我将以我最喜欢的类比结束,尽管当您刚刚问的是为什么连续运行的结果与您预期的不同时,它会更好地工作:
昨天我在修车。我把前轮取下来刹车,当我把轮子放回去时,我忘了拧紧螺母。我去开车,以 60 英里/小时的速度,前轮飞了起来,汽车转向一边,我撞到了路边的沟里。
今天去修理损坏的地方时,我不得不再次取下前轮。当我重新戴上它时,我忘了再次固定耳钉。但这一次,当我去开车时,前轮飞了,汽车转向另一边,我迎头撞上了半挂车。
为什么我得到不同的结果?我希望他们是一样的。
现在,这似乎是一个荒谬的类比,但实际上,对于我和任何有经验的 C 程序员来说,当有人问为什么一个程序在从事未定义的行为之后,生成或没有生成时,这听起来是多么荒谬可预测的结果。是的,计算机和计算机程序通常是确定性设备,但正如我之前所说,当您从事未定义的行为时,任何事情都可能发生。
推荐阅读
- fltk - FLTK双窗口和FLTK单窗口的区别
- linux - 如何在 Ubuntu Linux 上安装 tensorflow-gpu 1.15?
- javascript - 使用 setTimeout 的函数在后续调用中抛出
- javascript - Plotly.js 球体与 mesh3d
- proxy - 使用 nRF9160 + Zephyr RTOS 的 CoAP 客户端:代理 URI 长度问题
- python - 如何在 linux 上安装 OpenAi 的 Gym Atari 依赖项?
- amazon-web-services - AWS API Gateway HTTP API 参数映射与 Terraform
- javascript - 1 个动作 2 个提交(突变),但我必须等待我的第一个提交完成加载
- lua - 为什么相同的代码在 lua 中比在 julia 中慢?
- java - Java .jar 文件不运行,但它在 VSCode 中运行