为什么cout<< & r给出与cout不同的输出<< (无效*)及; R?

时间:2014-01-06 20:20:10

标签: c++ visual-c++ pointers char cout

这可能是一个愚蠢的问题,但我是C ++的新手,所以我还在愚弄基础知识。测试指针,我遇到的东西没有产生我预期的输出。

当我运行以下内容时:

char r ('m');
cout << r << endl;
cout << &r << endl;
cout << (void*)&r << endl;

我期待这个:

m
0042FC0F
0042FC0F

..但我得到了这个:

m
m╠╠╠╠ôNh│hⁿB
0042FC0F

我在考虑,因为r类型为charcout会将&r解释为char*,并且[出于某种原因]输出指针值 - 包含r地址的字节 - 作为一系列chars,但为什么第一个将是m内容指向的地址,而不是指针地址的第一个字节的char表示。好像cout&r解释为r,而不仅仅是输出'm',它继续输出更多的字符 - 从后续11个内存地址的字节值解释。为什么?为什么11?

我在64位Win7上使用MSVC ++(Visual Studio 2013)。


后记:我在这里得到了很多正确的答案(正如预期的那样,考虑到问题的微不足道的性质)。因为我只能接受一个,所以我把它作为我看到的第一个。但是,谢谢大家。

总结和扩展我的问题中提到的本能理论:

是的,cout确实将&r解释为char*,但由于char*是C ++中的“特殊事物”,实质上意味着一个以空字符结尾的字符串< / em>(而不是指针 [对单个char]),cout将尝试通过输出字符来打印出该字符串(从字节内容解释)内存地址r以后),直到遇到'\0'。这解释了11个额外的字符(它巧合地需要11个字节来点击NUL)。

为了完整性 - 使用int而不是char的相同代码按预期执行:

int s (3);
cout << s << endl;
cout << &s << endl;
cout << (void*)&s << endl;

产地:

3
002AF940
002AF940

6 个答案:

答案 0 :(得分:2)

专门针对operator<<字符串的char*重载。这将输出以null结尾的字符串,而不是地址。由于您传递此重载的指针不是一个以空字符结尾的字符串,因此当operator<<运行超过缓冲区末尾时,您还会获得未定义行为。

相反,void*重载会打印地址。

答案 1 :(得分:2)

char * C++C中的特殊内容,继承自C。在大多数情况下,它是char样式的字符串。它应该指向一个0 s数组,以'\0'(NUL字符'm')结尾。

因此它尝试打印此内容,然后在'\0'之后进入内存,寻找终止{{1}}。这使得它打印一些随机垃圾。这称为Undefined Behaviour

答案 2 :(得分:1)

因为operator<<超载,它将const char指针作为第二个参数并打印出一个字符串。采用void指针的重载仅打印地址。

答案 3 :(得分:1)

因为operator<<根据数据类型重载。

如果你给它char,它会假定你想要那个角色。

如果您给它void*,则假定您想要一个地址。

但是,如果你给它一个char*,它将它作为C风格的字符串并尝试输出它。由于C ++的最初意图是“C with classes”,因此必须处理C风格的字符串。

你最终得到所有垃圾的原因很简单,因为尽管你对编译器断言,它实际上不是一个C风格的字符串。具体来说,不保证在末尾有一个字符串终止的NUL字符,因此输出例程只会输出在它之后发生在内存中的任何内容。

这可能有用(如果那里有NUL),它可能会打印乱码(如果附近有NUL),或者它可能会摔得太厉害(如果在它到达记忆之前没有NUL则无法读取)。这是你应该依赖的东西。

答案 4 :(得分:0)

char *经常 - 通常是偶数 - 指向C风格的以空字符结尾的字符串(或字符串文字)的指针,并由ostreams处理。相比之下,void *明确指出需要指针值。

答案 5 :(得分:0)

operator<<()char const*的输出操作符(void const*)已超载。传递char*char const*的重载是更好的匹配并选择。此重载需要一个指向空终止字符串开头的指针。你给它一个指向个人char的指针,即你得到未定义的行为。

如果您想尝试使用明确定义的示例,可以使用

char s[] = { 'm', 0 };
std::cout << s[0] << '\n';
std::cout << &s[0] << '\n';
std::cout << static_cast<void*>(&s[0]) << '\n';