带有 char* 参数的 cout << 打印字符串,而不是指针值

cout << with char* argument prints string, not pointer value

提问人:Mr.Puff 提问时间:7/23/2013 最后编辑:GarrettMr.Puff 更新时间:8/9/2019 访问量:136297

问:

这:

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

打印而不是 的内存地址。为什么会这样?hello'h'

C++

评论

0赞 Melebius 7/20/2020
这回答了你的问题吗?为什么 cout 打印 char 数组与其他数组不同?

答:

13赞 sasha.sochka 7/23/2013 #1

您应该将代码更改为:

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

问题在于运算符对于指向 C 样式字符串的指针是重载的,用于打印字符串的内容。如果改为将其强制转换为原始指针,则将具有根据需要使用 iostreams 打印指针的默认行为。<<

-2赞 Ivan Smirnov 7/23/2013 #2

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

这就像你有

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

你只是被打印出来。1

评论

0赞 Mr.Puff 7/23/2013
为什么我没有得到内存地址?
1赞 Ivan Smirnov 7/23/2013
@Mr.Puff 如果要获取 char 指针的内存地址,应该先将其转换为 void 指针,因为 char 指针打印字符串的运算符是重载的。ostream <<
106赞 paxdiablo 7/23/2013 #3

这样做的原因是将 a 视为指向 C 样式字符串(的第一个字符)的指针,并按此打印。如果需要地址,则可以将其强制转换为以这种方式处理的指针,例如:std::coutchar *

cout << (void *) terry;

(或者,如果您担心会抛弃 Constness,请使用 Cast,这在这种特殊情况下不是问题)。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

请注意,在使用 时,您应该确保不要试图抛弃 constness with(这就是用途)。这是较新的 C++ 强制转换完成的检查之一,旧式强制转换没有此限制。static_caststatic_cast <void *>const_cast

评论

2赞 Keith Thompson 7/23/2013
它不会将值视为 C 样式字符串;它将其视为指向 C 样式字符串(的第一个字符)的指针char*
4赞 paxdiablo 7/23/2013
这只对那些不知道自己在做什么的人很危险。在这种情况下,放弃一致性是无关紧要的,因为您没有对指针执行任何重要操作。是的,如果你投射指针然后熄灭并错误地使用它,我会同意,但我希望一种语言的从业者能够学习 hozw 安全地使用它。我没有让我的儿子开始使用我更危险的工具,直到他证明他知道它们的问题:-)
4赞 gx_ 7/23/2013
我认为在 C++ 中使用 C 样式强制转换只有 2 个原因:1. 强制转换为无法访问的基类;2.懒得多输入几个字符。
9赞 paxdiablo 7/24/2013
你说懒惰好像是一件坏事。只有当有实际的递减效应时,它才是坏的,否则它被称为效率。在这种特殊情况下使用旧式强制转换没有问题,它们与其他任何语言一样都是 C++ 语言的一部分(即使像 cstdio 这样的东西也是可以接受的,只要你了解这些问题)。
2赞 paxdiablo 7/24/2013
但是,我看得出来,我不太可能说服你。纯粹主义者和实用主义者之间的战斗似乎在这里抬头,双方都有自己的观点,但我们不妨讨论 vi 与 emacs :-)所以我建议你用你的良心投票,我们会让人民来决定。我将添加较新的样式作为选项,但我仍然认为在这种情况下没有必要。
2赞 Richard Fung 7/23/2013 #4

cout重载,因此当您给它一个 时,它将打印为指向 C 样式字符串的指针。因此,它会打印出字符,直到它命中 null 终止字符。char*

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

评论

3赞 paxdiablo 7/4/2015
printf它本身并不能决定它的打印方式,你仍然必须使用正确的格式说明符,就像你必须在 C++ 中使用相同的类型一样。例如,with 将具有与 .若要获取指针,请使用格式说明符。printf%scoutchar *%p
29赞 Keith Thompson 7/23/2013 #5

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

如果给它一个 或 ,它会将操作数视为指向 C 样式字符串(的第一个字符)的指针,并打印该字符串的内容:char*const char*

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

将 or 视为指向 C 样式字符串的指针是一种特例,也是唯一一种(我能想到的)导致打印操作数值以外的内容的情况。其原因可以追溯到 C++ 在 C 中的根源,它没有“字符串”类型,而是通过指针操作字符串。char*const char*operator<<char*

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

评论

0赞 gx_ 7/24/2013
我能想到的另一个“特殊”情况是尝试打印一个函数指针,它将选择重载(除非该函数具有流操作器的签名): ideone.com/OkutRD(诚然,它打印了指针的“值”转换为 ,所以这比情况“不那么特殊”)boolboolconst char*
0赞 asn 1/13/2019
@KeithThompson 因此,这意味着是 of 使字符串被打印出来,而不是指针值,而在类似的情况下,指针值将被打印出来,而不是值。我在这里是对的吗?overloaded versionoperator<<int*
5赞 IS4 1/18/2019 #6

std::cout被定义为 的这个定义。std::ostreamoperator<<

值得注意的是这一行:

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

当您与 类型的参数一起使用时,将选择此选项。<<char*

任何其他非字符指针类型的情况如下:

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

这继续用于 std::num_put 用于格式化数值。因此,指针在数字上是互重的,就像在 C 格式函数中一样。%p