为什么我们总是需要使用零来memset(清空)内存?

3
每当我们使用memset时,我们都会将其设置为零。
为什么?为什么不用1或2或其他东西呢?
另外,将结构体设置为0似乎可以工作,但将其设置为1就不行:
typedef struct abc{
    int a;
} abc;

int main()
{
    abc* ab;
    memset(ab, 0, sizeof(abc));// it sets abc->a = 0; correct
}

但是,如果我使用1而不是0,就像这样:

memset(ab, 1, sizeof(abc));

那么abc->a的值为垃圾或不等于1。

为什么呢?


1
因为memset将所有字节设置为指定值,而不是整个整数。 - sgarizvi
1
你的程序从未分配指针ab的目标。该程序是未定义行为(但这不一定是ab->a不是1的原因)。 - Pascal Cuoq
因为0是初始值。 - Sergei Nikulov
@sgar91:你能详细解释一下吗? - Rasmi Ranjan Nayak
1
选择一种语言。然后为指针分配数据地址或声明适当类型(abc)的变量并使用该地址。如写作 abc* ab; 声明一个具有不确定值的指针(意味着您不知道它是什么)。将其用作 memset() 调用中的写入目标是未定义行为。此外,如果是 C,则您的 main() 程序暗示了一个 int 返回值,并且如果是标准 C++ 则无法编译。将其声明为 int main() 并返回一个值(EXIT_SUCCESS 或 EXIT_FAILURE)。 - WhozCraig
对于C++来说,答案非常简单:不要使用memset。改用std::fill(或std::fill_n)即可。 - Grizzly
5个回答

13

您并不总是需要使用memset将其设置为0,这只是最常见(也是最有用)的操作。

memset将每个字节设置为给定值。一个int由4个字节组成,因此,当将memset设置为1时,您将每个字节都设置为1,然后您将得到00000001 | 00000001 | 00000001 | 000000012=1684300910(前面的数字是二进制的,最后一个是十进制的)。

另外 - 请注意,您从未为ab分配内存。即使您的代码现在可以工作,它也不安全。正确的方式如下:

abc ab;
memset(&ab, 0, sizeof(abc));

4
正如其他人所提到的, 0 在很大程度上是任意的。然而,如果我们不得不选择理由,那是为了方便(以牺牲安全为代价 - 如果您依赖变量,应该优先显式初始化变量):
  • 0在大多数情况下被理解为整数(有符号或无符号)的初始值,因为它表示0而无论宽度或字节顺序如何。
  • 0是char*字符串的结束符。
  • 浮点数通常为0.0。
  • 在C中,0通常是NULL,在C++中保证是NULL

1
@AlexeyFrunze:除了语言标准外,还有其他标准,其中一些更加普遍。 - Benjamin Lindley
@BenjaminLindley 那么,您认为语言标准并不保证0.0用所有零位表示? - Alexey Frunze
@AlexeyFrunze:我不知道它是否这样做。但我确信它是一个真正的保证(即使没有语言标准指定),比一些实际上由语言标准指定的东西更强。 - Benjamin Lindley
2
@BenjaminLindley 它并不提供这样的保证。它只描述了符合规范的模型,而不是它们的位表示。 - Alexey Frunze
1
@AlexeyFrunze:我在谈论浮点数标准。我认为,如果你依赖于浮点数中0的二进制表示,你的代码并不会变得不够可移植,因为只有少数几个浮点数系统被广泛使用(在超过1个人使用的环境中),它们都以相同的方式表示0.0。 - Benjamin Lindley
显示剩余6条评论

2
使用 memset() 设置内存的值取决于您的需求。没有人阻止您使用任何其他值来初始化内存。

1
在您的程序中,当变量被定义时,默认情况下它将指向任何位置,并且之前可能存在任何垃圾数据。
通常我们使用memset (0)来确保变量初始化为零,以便在程序后期我们可以信任变量分配的值是真正的分配值而不是任何垃圾值。
希望这有所帮助.....

为什么只有0?为什么不能用其他值? - Rasmi Ranjan Nayak
因为“0”是设置任何值的最常见值。现在假设您将值设置为“3”。现在,任何其他由其他人编写的应用程序都会读取相同的结构。现在他会认为ab->a = 3是一个有效的值,并将其用于进一步处理数据。但是,如果您发送ab->a = 0,则他将知道您的结构不携带任何有效数据,并将在该点停止执行。 - Abhineet
因为我们都知道零代表着什么都没有(空)。这就是为什么。 你可以尝试使用1、2直到255的任何值,也可以在比较时使用它。但你应该知道memset适用于所有字节。 例如,在你的情况下,结构体具有int成员,并假设int为4个字节,它将分配1到所有4个字节,所以当你打印值时,你不会得到1,而是十进制4369或0x1111。所以要小心。 - Kinjal Patel
现在再假设你的结构体中有另一个成员"char b[20]"。现在你给它赋了一些随机值,比如ab->b = "nayak"(注意你忘记在末尾放置"\0"<NULL>字符)。现在当我将"ab->b"读取为字符串时,我永远不会遇到NULL,因此会尝试读取缓冲区之外的内容,或者更糟糕的是可能会发生任何未定义的后果。在这种情况下,将结构体memset为0将非常方便,因为"Nayak"之后的下一个字节将是"0"。因此,即使您犯了像忘记NULL这样的错误,您的代码也不会崩溃。 - Abhineet

1

首先你的程序有未定义行为,原因是 abc* ab; 的内存从未分配!

其次,字符串必须以“null”终止,这意味着它已结束,因此我们在memset中使用null。但你可以使用任何你想要的值...


谈论“零”而不是“空值”会更加清晰明了。 - alk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接