【发布时间】:2013-07-22 17:07:45
【问题描述】:
这个:
const char * terry = "hello";
cout<<terry;
打印hello 而不是'h' 的内存地址。为什么会这样?
【问题讨论】:
标签: c++
这个:
const char * terry = "hello";
cout<<terry;
打印hello 而不是'h' 的内存地址。为什么会这样?
【问题讨论】:
标签: c++
原因是std::cout 将char * 视为指向C 样式字符串(的第一个字符)的指针并按原样打印。如果你想要 address 而不是,你可以将它转换为一个 不 那样处理的指针,例如:
cout << (void *) terry;
(如果您担心抛弃 constness,则可以使用 const void * 演员表,在这种特殊情况下这不是问题)。
如果您是纯粹主义者而不是实用主义者,您还可以使用 C++ static_cast,如下所示:
cout << static_cast <const void *> (terry);
虽然在这种特殊情况下没有必要,但转换为 void * 可以正常工作。以下示例代码显示了所有这些选项的实际作用:
#include <iostream>
int main (void) {
const char *terry = "hello";
std::cout << terry << '\n';
std::cout << (void *) terry << '\n';
std::cout << (const void *) terry << '\n';
std::cout << static_cast<const void *> (terry) << '\n';
return 0;
}
正在输出(地址在你的环境中可能不同):
hello
0x8048870
0x8048870
0x8048870
请注意,在使用static_cast 时,您应该确保不要尝试用static_cast <void *> 抛弃常量(这就是const_cast 的用途)。这是较新的 C++ 转换所做的检查之一,而旧式转换没有此限制。
【讨论】:
char* 值视为C 风格的字符串;它将其视为指向 C 样式字符串(的第一个字符)的 指针。
std::cout 上的 << 运算符重载。它的行为取决于右操作数的类型。 (实际上是几个不同的函数,都命名为operator<<;编译器决定调用哪一个。)
如果您给它一个char* 或const char*,它会将操作数视为指向C 样式字符串(的第一个字符)的指针,并打印该字符串的内容:
const char * terry = "hello";
cout << terry; // prints "hello"
如果你给它一个char 值,它会将该值打印为一个字符:
cout << *terry; // prints "h"
cout << terry[0]; // the same
如果你给它一个void* 类型的指针,它会打印那个指针值(以某种实现定义的方式,通常是十六进制):
cout << static_cast<const void*>(terry); // prints something like 0x4008e4
将char* 或const char* 视为指向C 样式字符串的指针是一种特殊情况,并且唯一(我能想到的)导致operator<< 打印的值不是操作数。原因可以追溯到 C++ 在 C 中的根源,它没有“字符串”类型,而是通过 char* 指针来操作字符串。
operator<<、各种整数和浮点数值类型、std::string 等还有许多其他重载。
【讨论】:
bool重载(除非该函数具有流操纵器的签名):ideone.com/OkutRD(诚然,它会打印转换为bool 的指针的“值”,所以这比const char* 的情况“不那么特别”)
operator<< 的overloaded version 使字符串被打印,而不是指针值,而在类似int* 的情况下,指针值将被打印而不是价值。我说的对吗?
你应该把你的代码改成这样:
cout << static_cast<const void*>(terry);
问题在于 << 运算符被重载,用于指向 C 样式字符串的指针以打印字符串的内容。如果您将其强制转换为原始指针,您将拥有使用 iostreams 打印指针的默认行为。
【讨论】:
std::cout 定义为 std::ostream,this 定义为 operator<<。
尤其是这一行:
template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,
const char* s );
当您将<< 与char* 类型的参数一起使用时,将被选中。
任何其他非字符指针类型的大小写为here:
basic_ostream& operator<<( const void* value );
这继续到std::num_put,它用于格式化数值。因此,指针在 C 格式化函数中的数字解释类似于 %p。
【讨论】:
cout 被重载,所以当你给它一个char* 时,它会打印为一个指向 C 风格字符串的指针。因此,它会打印出字符,直到遇到空终止字符。
如果您使用printf 而不是cout,您会看到地址。您还可以将指针转换为另一种类型,例如(void*),您还可以获得地址。
【讨论】:
printf 本身并不决定如何打印,您仍然必须使用正确的格式说明符,就像在 C++ 中必须使用相同的类型一样。例如,printf 和 %s 与 cout 和 char * 的问题完全相同。要获取指针,您可以使用格式说明符 %p。
"hello" 是一个字符串,即 char 数组。 const char* 是一个指向这个数组的指针,所以当你取消引用这个指针时,你会得到第一个元素的值。
如果你有
int a[] = {1, 2, 3};
int *b = a;
cout << *b << endl;
你只会得到1 打印出来。
【讨论】: