cout <<与char *参数一起输出字符串,而不是指针值


Answers:


86

这样做的原因是,std::cout它将achar *当作指向C样式字符串(第一个字符)的指针,并像这样打印它。如果要使用该地址,则可以将其强制转换为未经这种处理的指针,例如:

cout << (void *) terry;

const void *如果担心释放常量性,则可以使用强制类型转换,在这种情况下这不是问题)。


如果您更注重纯粹主义者而不是实用主义者,那么还可以按照以下方式使用C ++ static_cast

cout << static_cast <const void *> (terry);

尽管在这种特殊情况下是不必要的,但将a强制转换为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,您应确保不要试图用舍弃constness static_cast <void *>(这就是这样做的const_cast目的)。这是较新的C ++强制转换进行的检查之一,而旧样式的强制转换没有此限制。


1
它不会将char*值视为C样式的字符串。它将其视为指向C样式字符串(的第一个字符)的指针
基思·汤普森

3
这对那些不知道自己在做什么的人来说很危险。在这种情况下,常量的删除是无关紧要的,因为您无需对指针进行任何重要操作。是的,如果您抛开指针然后不正确地使用它,我同意,但是我希望某种语言的从业者可以学习hozw来安全地使用它。在儿子证明自己知道与他们有关的问题之前,我没有让他的儿子开始使用更危险的工具:-)
paxdiablo

3
我只看到在C ++中使用C样式转换的两个原因:1.转换为不可访问的基类;2.懒惰再输入几个字符。
gx_

7
您谈论懒惰似乎是一件坏事。只有存在实际的递减效果才是坏的,否则就是效率。在这种特殊情况下使用老式强制类型转换没有任何问题,它们与其他任何语言一样,都是C ++语言的一部分(即使您了解问题,也可以使用cstdio之类的东西)。
paxdiablo

2
但是,我看到我不太可能说服您。纯粹主义者和实用主义者之间的斗争似乎在这里抬头,双方都有自己的观点,但我们不妨讨论vi与emacs :-)所以我建议您投票赞成自己的良心,让人民决定。我将添加较新的样式作为一个选项,但是在这种情况下,我仍然没有必要这样做。
paxdiablo

22

上的<<操作员std::cout超载。它的行为取决于正确操作数的类型。(实际上是几个不同的函数,都被命名operator<<;编译器决定调用哪个函数。)

如果将其赋予char*or或const char*,则它将操作数视为指向C样式字符串(第一个字符)的指针,并输出该字符串的内容:

const char * terry = "hello";
cout << terry; // prints "hello"

如果给它一个char值,它将把该值打印为字符:

cout << *terry;   // prints "h"
cout << terry[0]; // the same

如果为它提供type的指针void*,它将打印该指针值(以某种实现定义的方式,通常为十六进制):

cout << static_cast<const void*>(terry); // prints something like 0x4008e4

将achar*const char*C风格的字符串作为指针是一种特殊情况,并且是唯一(导致我想到的)导致operator<<打印除操作数值以外的内容的字符串。这样做的原因可以追溯到C ++的C语言根源,C语言中没有“字符串”类型,而是通过char*指针操作字符串。

对于operator<<,对于各种整数和浮点数字类型,对于std::string,还有许多其他重载,等等。


我可以想到的另一种“特殊”情况是尝试打印一个函数指针,该指针将选择bool重载(除非该函数具有流操纵器的签名):ideone.com/OkutRD(诚​​然,它会打印以下内容的“值”:指针转换为bool,因此这比const char*情况“特殊” )
gx_13年

@KeithThompson所以,这意味着它的overloaded versionoperator<<,使串得到印刷,而不是指针值,而在类似情况下int*的指针值将得到打印,而不是价值。我在这里正确吗?
ajaysinghnegi

11

您应该将代码更改为此:

cout << static_cast<const void*>(terry);

问题在于,<<用于打印C样式字符串的指针的操作符已重载,以打印字符串的内容。如果将其强制转换为原始指针,则将具有使用iostreams打印指针的默认行为。


3

std::cout的定义std::ostream相同operator<<

值得注意的是这一行:

template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,
                                     const char* s );

<<与type参数一起使用时,将选择此选项char*

任何其他非字符指针型的情况下,去这里

basic_ostream& operator<<( const void* value );

继续std::num_put进行格式化数字值的操作。因此,像%p在C格式化函数中一样,在数字上解释指针。


1

cout重载,因此当您给它一个时char*,它将作为指向C样式字符串的指针进行打印。因此,它将打印出字符,直到遇到空终止符为止。

如果您使用printf而不是cout,则会看到该地址。您还可以将指针强制转换为另一种类型,例如(void*),您还将获得地址。


2
printf本身不决定如何打印,您仍然必须使用正确的格式说明符,以相同的方式在C ++中使用相同的类型。例如,printf%s将具有完全相同的问题,因为coutchar *。要获取指针,可以使用格式说明符%p
paxdiablo

-1

“ hello”是一个字符串,即char数组。const char*是指向此数组的指针,因此当取消引用该指针时,将获得第一个元素的值。

就像你有

int a[] = {1, 2, 3};
int *b = a;
cout << *b << endl;

您刚1打印出来。


为什么我没有获取内存地址?
帕夫先生2013年

1
@ Mr.Puff如果要获取char指针的内存地址,则应将其强制转换为void指针,因为ostream <<char指针会重载运算符以打印字符串。
Ivan Smirnov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.