为什么这个内存引用了segfault?

use*_*936 -2 c memory-management

double fun(int i)
{
 volatile double d[1] = {3.14};
 volatile long int a[2];
 a[i] = 1073741824;
 return d[0];
}
Run Code Online (Sandbox Code Playgroud)

有趣(0)➙3.14

有趣的(1)➙3.14

有趣的(2)➙3.1399998664856

有趣的(3)➙2.00000061035156

好玩(4)➙3.14,然后分段错误

谁可以向我解释在这个例子中发生了什么以及为什么在调用func(2)时段错不会出现?为什么返回值不总是3.14?

bar*_*nos 5

您声明一个包含2个条目的数组:

volatile long int a[2];
Run Code Online (Sandbox Code Playgroud)

然后,您使用索引访问此数组:

a[i] = 1073741824;
Run Code Online (Sandbox Code Playgroud)

由于C中的数组索引从0开始,因此任何大于1的索引都会产生未定义的行为.

在你的程序中,你用函数调用函数i=2,i=3i=4.

这些函数调用中的每一个都独立地产生未定义的行为.

未定义的行为意味着任何事情都可能发生.

您只是遇到分段错误这一事实fun(4)仅仅是巧合.


补充:

免责声明:以下分析并不意味着在每个平台上,甚至在每次执行时都会出现相同的行为; 它只是为了解释观察到的"奇数"返回值.

  • 4字节的十六进制值10737418240x40000000
  • 8字节的十六进制值3.140x40091EB851EB851F(符合IEEE 754)
  • 通过写0x40000000a[2],你已经在覆盖的8字节的值的4个最低显著字节d[0](而不会引起分段故障),因此对其进行更改0x40091EB851EB851F0x40091EB840000000,它代表(IEEE 754)的浮点值3.1399998664856
  • 通过编写0x40000000a[3],你已经覆盖在的8字节的值的4个最显著字节d[0](而不会造成分段错误),从而对其进行更改0x40091EB851EB851F0x4000000051EB851F,它代表(IEEE 754)的浮点值2.0000006103516