我确实在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 ++的新手,我似乎无法理解。
答案 0 :(得分:4)
标准中将所发生的事情描述为数组到指针的转换。
4.2数组到指针的转换[conv.array]
“N T数组”或“未知数组的数组”的左值或右值 “可以将T”转换为“指向T”的类型的右值。结果 是指向数组第一个元素的指针。
上面说过,在第一次调用memset
szMain
时会转换为指针(更具体地说是指向char
的指针),存储数组第一个元素的地址。
在第二次调用中,&szMain
将产生类型为char (*)[512]
的指针,即。指向与szMain
具有相同类型的数组的指针,存储数组本身的地址。
这两个表达式都会产生相同的确切值,因为szMain
的开头位于与它的第一个元素(szMain[0]
)相同的地址,但请注意,不是同一类型。
memset
接受void*
作为第一个参数,因此可以隐式使用任何指针类型来调用该函数。
答案 1 :(得分:3)
szMain
是数组的标识符。在大多数情况下,数组标识符会衰减成为指向数组中第一个元素的指针,换句话说就是&szMain[0]
。
所以在你的第一个例子中,你传递memset
数组第一个元素的地址。在第二个示例中,您将传递数组本身的地址。但是,这些地址完全相同。
答案 2 :(得分:2)
是的,在这种情况下,两者具有相同的行为,但情况并非总是如此。
数组名称的大多数用法都给出了数组第一个元素的地址。对于T数组,指针的类型将为T *
。
如果明确地取代数组的地址,则获得相同的地址,但是不同的类型(“指向类型为T的N个对象的数组的指针”而不是“指向T的指针”)。
在这种情况下,您传递的地址将转换为void *
,因此会立即丢弃类型的差异 - 但如果您在另一个不立即丢弃类型差异的上下文中使用它们,不一定会产生同样的效果。例如,如果您想要取消初始化数组的第一个元素,您可能会执行以下操作:
memset(szMain+1, 'a', sizeof(szMain));
由于类型(在这种情况下)是“指向char的指针”,它将根据需要从数组中的第二个char开始。但是,如果你这样做了:
memset(&szMain+1, 'a', sizeof(szMain));
它不会添加1,而是添加一个数组的大小,因此您将在数组结束后传递地址,而不是第二个元素的地址。
顺便说一句:如果你想要'a',我建议你直接使用它,就像我在上面那样,而不是像在问题中那样用十六进制编码值。至少,它更具可读性。它在理论上也更具可移植性,但很少有人真正关心十六进制值无法正常工作的机器(主要是IBM大型机)。