c语言 - 内存集对浮点数组做了什么?



我最近在网上发现了一段代码,看起来有点像这样:

#include <stdio.h>
#include <string.h>
int main() {
float m[10];
memset(m, 0, 20); 
}

我还看到了一个片段,其中是这样的,我相信是正确的:

memset(m, 0, sizeof m); 

尝试使用此代码片段打印出第一个示例的所有值时:

for (int i = 0; i < 20; i++) {
printf("%f, n", m[i]);
}

它产生如下输出:

0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
-0.000000, 
-4587372491414098149376.000000, 
-0.000013, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000

值在重新编译时更改的位置。

现在我有几个问题:

  • 为什么 memset 写入float数组的次数可以超过分配的内容,为什么不能使用char数组执行此操作?
  • 为什么如此不一致?
  • 例如,为什么将第二个值更改为memset的值更改为1不会更改输出?

为什么 memset 写入float数组的次数比分配的多,为什么不能用char数组来做到这一点?

memset(m, 0, 20);,正如问题最初显示的那样,写的不超过分配的。通常,float在 C 实现中是 4 个字节,因此float m[10];分配 40 个字节,memset(m, 0, 20);写入 20 个字节。

在新代码中,memset(m, 0, sizeof m);写入的字节数与m一样多,不多也不少。

如果memset被要求写更多,你可以尝试这样做的原因是C实现通常不进行安全检查操作,而C标准也不要求他们这样做。

为什么如此不一致?

没有什么不一致的。memset将零写入m的前20个字节,这是浮点零的编码,格式通常用于float(IEEE-754二进制32,也称为"单精度")。

之后的字节没有写入,因此打印它们使用未初始化的数据。C 标准说未初始化对象的值是不确定的。一个常见的结果是程序使用内存中已经发生的任何内容。这可能是零,也可能是别的什么。

但是,使用 循环for (int i = 0; i < 20; i++),您超越了m中的 10 个元素。那么访问m[i]的行为不是由 C 标准定义的。如上所述,一个常见的结果是程序访问计算的内存并使用碰巧存在的内存。但是,也可能出现各种其他行为,包括由于尝试访问未映射的内存或编译器在优化期间将未定义的代码替换为备用代码而崩溃。

为什么更改memset的第二个值不会更改输出?

它会,具体取决于您将其更改为什么。字节的某些值可能会导致float值太小,它们仍打印为"0.000000"。例如,如果将字节设置为 1,则使 32 位0x01010101在每个float中,则它们表示float值 8,454,401•2− 148 = 2.36942782761723955384693006253917004604239556833255136345174597127722672385008451101384707726538181304931640625•10−38

如果使用 64 作为要memset的第二个参数,则位将设置为0x40404040,其编码值为 3.0039215087890625,因此将打印"3.003922"。

Memset

float数组没有任何作用。 你只有一个 10 个浮点数的数组,你使用了一个覆盖 20 个的循环,这意味着,因为 C 不检查数组边界......您已经远远超出了数组的末尾,并将不是的东西解释为浮点数。 我不会在这里重复其他答案中已经说过的内容,但是您在调整 C 对象的大小时遇到了问题。sizeof接线员是你的朋友。 在将参数传递给memcpymalloc等函数而不是使用常量时使用它,因此如果您调整对象的大小,您仍然可以,而无需更改常量值。

最新更新