这可能是一个愚蠢的问题,但我是C ++的新手,所以我还在愚弄基础知识。测试指针,我遇到的东西没有产生我预期的输出。
当我运行以下内容时:
char r ('m');
cout << r << endl;
cout << &r << endl;
cout << (void*)&r << endl;
我期待这个:
m
0042FC0F
0042FC0F
..但我得到了这个:
m
m╠╠╠╠ôNh│hⁿB
0042FC0F
我在考虑,因为r
类型为char
,cout
会将&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
答案 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';