考虑一下这段代码的输出结果:
它输出了"ab"(即
char A = 'a';
char B[] = "b";
cout<<&A;
它输出了"ab"(即
A
和B
的连接),我想知道为什么。请解释一下。char A = 'a';
char B[] = "b";
cout<<&A;
A
和B
的连接),我想知道为什么。请解释一下。&A
是一个char *
。字符串通常由char *
表示,需要在字符串的末尾添加'\0'
字符来标识字符串结束。
&A
指向单个char
,没有紧随其后的'\0'
。因此,尝试打印该文本字符串将导致未定义的行为。void*
。这也是在 stdio 中使用 %p
的正确方式。 - StoryTeller - Unslander Monica由于类型为char *
的对象的运算符<<
重载的方式输出指向char *
类型指针所指向的字符串,因此您得到了意外的结果。
看起来您的编译器将数组B
放在字符A
之后,它们在内存中看起来像一个字符串。
'a' 'b' '\0'
| |
A B
A
是否会在内存中先于B
,或者B
会在A
之前,并且是否由于填充字节而在对象之间存在间隙。)cout<< ( void * )&A;
或者
cout<< ( const void * )&A;
cout<< static_cast<void *>( &A );
cout<< static_cast<const void *>( &A );
无需指定非常量对象的指针是否为const
限定符,因为它将在运算符中隐式转换为类型const void *
。
basic_ostream<charT,traits>& operator<<(const void* p);
cout
期望char*
参数指向一个以零结尾的字符串。但是&A
没有以零结尾,因此前提条件失败,导致未定义行为。
未定义行为无法真正解释,因为标准允许发生任何事情。显示更多字符是可能的结果。崩溃也是一种可能。或者其他的什么。
我想知道为什么
因为流插入运算符要求传递给它的任何字符指针都必须指向以空字符结尾的字符串。传递给 cout
的指针指向的是不以空字符结尾的字符串 A
。由于操作的前提条件(要求)未满足,行为是未定义的。
插入运算符有两个相关的重载(我已经简化了模板细节,以及其中一个是成员重载,另一个不是):
ostream& operator<< (const void*);
ostream& operator<< (const char*);
void*
并使用前一个重载,指针被输出为内存地址。但是,后者更适合字符指针,并且要求参数为以null结尾的字符串。void*
。std::cout << "Hello World!";
很方便地打印出“Hello World”,而不是字符串字面量所在的内存地址。这是一个依赖于编译器的行为。通常情况下,A和B会在堆栈上相继分配。获取A的地址看起来像以零结尾的字符串“ab”。不要这样做!你依赖于编译器构建的堆栈帧布局。
因为你的字符没有以空字符结尾。 这将导致行为未定义。
你的编译器把包含 'b' 和 '\0' 的字符串立即放在字符 'a' 后面,因此一旦你将A字符作为字符串打印出来,它会找到 'a',然后是 'b' 然后是 '\0',因此你打印了 'ab'
cout
这个函数。请不要滥用标签。 - StoryTeller - Unslander Monicacout
,你的构造也不是合法的C代码。它的工作方式由C++标准规定。如果你关心C,你应该发布有效的C代码。 - StoryTeller - Unslander Monica