C ++内存管理的奇怪之处

时间:2017-01-17 12:06:34

标签: c++ memory-management

考虑此代码的输出:

char A = 'a';
char B[] = "b";
cout<<&A;

输出&#34; ab&#34; (AB的串联)我想知道为什么。请解释一下。

7 个答案:

答案 0 :(得分:15)

因为&Achar *。由char *表示的字符串需要具有'\0'终止字节。

&A指向单个char,没有跟随'\0'。因此,尝试打印此文本字符串会导致未定义的行为。

答案 1 :(得分:4)

您收到了意外的结果,因为类型为operator <<的对象的char *被重载,导致它输出由char *类型的指针指向的字符串。

您的编译器似乎将数组B放在字符A之后,并且在内存中它们看起来像一个字符串。

'a' 'b' '\0'
|   |
A   B

(C ++标准中未指明A将在B之前,B将在A之前位于内存中,以及填充是否会出现间隙对象之间的字节。)

如果要输出对象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);

答案 2 :(得分:1)

  

我想知道为什么

因为流插入运算符要求传递给它的任何字符指针必须指向空终止字符串。传递给cout的指针指向A,它不是空终止的字符串。由于不满足操作的前提条件(要求),因此行为未定义。

插入操作符有两个相关的重载(我已经简化了模板细节,其中一个是成员重载,另一个不是):

ostream& operator<< (const void*);
ostream& operator<< (const char*);

所有其他指针隐式转换为void*并使用前一个重载,指针被输出为内存地址。但后者是字符指针的优先重载,并且该参数必须是一个以空字符结尾的字符串。

因此,因为字符指针被解释为以空字符结尾的字符串,所以打印字符地址的天真尝试不起作用。解决方案:在传递给流之前,将指针明确地转换为void*

这些流是以这种方式设计的,以便方便地支持空终止字符串,例如字符串文字被认为是(并且是)比地址更典型地流式传输。例如,std::cout << "Hello World!";很方便。打印“Hello World”而不是字符串文字所在的内存地址。

答案 3 :(得分:1)

cout期望char*参数指向零终止字符串。但&A并非零终止,因此前置条件失败,这会导致未定义的行为。

无法真正解释未定义的行为,因为标准允许任何发生。显示更多字符是一种可能的结果。就像崩溃一样。或者别的什么。

答案 4 :(得分:0)

这是一种依赖于编译器的行为。通常,A nad B将在堆栈上一个接一个地分配。取A的地址将看起来像零终止字符串“ab”。 不要这样做!您依赖于编译器正在构建的堆栈帧布局。

答案 5 :(得分:0)

因为您的char未终止null。 对此的行为将是UNDEFINED。

答案 6 :(得分:0)

你的编译器在字符'a'后面立即放置了包含'b'和'\ 0'的字符串,所以一旦你将 A 字符打印成字符串,它就会找到'a',然后是'b'后跟'\ 0',因此你打印'ab'