2

我确实在 msdn 和 cplusplus.com 上阅读了 memset 的用法,我知道(如果我错了,请纠正我):

int p =3;
// p = object value
// &p = memory address where p is stored

那么有什么区别:

char szMain[512];
memset( szMain, 0x61, sizeof( szMain ) );
cout << szMain[4];

和:

char szMain[512];
memset( &szMain, 0x61, sizeof( szMain ) );
cout << szMain[4];

(0x61 = a,ASCII 表十六进制)

为什么两者都有相同的行为?如果这不是一个建设性的问题,请原谅我。我是 C++ 的新手,我似乎无法理解。

4

3 回答 3

4

正在发生的事情在标准中被描述为数组到指针的转换

4.2 数组到指针的转换[conv.array]

“NT数组”或“T的未知边界数组”类型的左值或右值可以转换为“指向T的指针”类型的右值。结果是指向数组第一个元素的指针。


上面说,在您的第一次调用中,memset szMain将转换为char存储数组第一个元素的地址的指针(更具体地说是指向的指针)。

在第二次调用中,&szMain将产生一个类型的指针char (*)[512],即。指向与 具有相同类型的数组的指针szMain,存储数组本身的地址。

这两个表达式都将产生相同的精确值,因为它的开头与szMain它的第一个元素 ( ) 位于相同的地址szMain[0],但请注意它们不是同一类型。


memset接受 avoid*作为第一个参数,因此可以隐式使用任何指针类型来调用函数。

于 2012-06-25T23:30:47.420 回答
3

szMain是数组的标识符。在大多数情况下,数组标识符衰减为指向数组中第一个元素的指针,换句话说&szMain[0]

所以在你的第一个例子中,你传递memset了数组第一个元素的地址。在第二个示例中,您将数组本身的地址传递给它。但是,这些是完全相同的地址。

于 2012-06-25T23:25:35.220 回答
2

是的,在这种情况下,两者具有相同的行为,但不一定总是如此。

数组名称的大多数用法都给出了数组第一个元素的地址。对于 T 的数组,指针的类型将是T *

如果您明确地取而代之的是数组的地址,您将获得相同的地址,但类型不同(“指向 T 类型的 N 个对象的数组的指针”而不是“指向 T 的指针”)。

在这种情况下,您传递的地址将转换为 a void *,因此类型差异会立即被丢弃 - 但如果您在另一个不会立即丢弃类型差异的上下文中使用它们,它们不一定具有相同的效果. 举个例子,如果你想让数组的第一个元素不被初始化,你可以这样做:

memset(szMain+1, 'a', sizeof(szMain));

由于存在类型(在这种情况下)“指向字符的指针”,因此它将根据需要从数组中的第二个字符开始。但是,如果您这样做了:

memset(&szMain+1, 'a', sizeof(szMain));

它将添加一个数组的大小,而不是加 1,因此您将在数组末尾之后传递地址,而不是第二个元素的地址。

顺便说一句:如果你想要'a',我建议像上面那样直接使用它,而不是像你在问题中那样用十六进制编码值。至少,它更具可读性。它在理论上也更便携,尽管很少有人真正关心十六进制值无法正常工作的机器(主要是 IBM 大型机)。

于 2012-06-25T23:37:35.190 回答