1

我正在寻找对以下 3 个示例的更好理解。

这是我对以下代码示例的问题。

  • 前任。1.例子有意义,它输出了存储int a的地址。
  • 前任。2. 意义不大。我认为这是因为 char 本身指向 char?
  • 前任。3. 让我困惑。在输出中,第一个 char 输出始终是存储在 char 中的 on。但是附加字符是什么?为什么在将 &a 保存到 char 指针后它们会出现?

最后,我如何输出保存 char 变量的内存位置的地址?

前任。1

main(void) 
{
  int a = 1;
  cout << &a;
}

输出内存地址 ex。0x7fff4241b7b4

例 2。

main(void) 
{
  char a = 'a';
  cout << &a;
}

输出字符 a。前任。一个

前任。3.

main(void) 
{
  char a = 'a';
  char *b = &a;
  cout << &a;
}

输出a��:��

4

2 回答 2

6

第一个指针匹配operator<<(const void*)输出指针值的那个;第二个和第三个匹配operator<<(const char*)将输出一个以空字符结尾的字符串。

chara是堆栈上的值,因此第一个字节之后的字节是否为空是完全未定义的,幸运的是,在中间情况下它后面跟着一个空字节,但在第三种情况下,后面的一些字节不是空字节并且您会收到损坏的 UTF-8 字符。您设置指针这一事实不会影响程序的运行,但堆栈帧的设置方式不同,例如 GCC 会发出movb $97, -9(%rbp)汇编器操作码来设置堆栈上的字节,将 char 放在非对齐地址中。我电脑上的堆栈布局是这样的(64位)

| x | x | x | x | x | x | a | b | b | b | b | b | b | b | b |
                                                            ^
                                                           RPB

因此a在堆栈上直接跟随 b 指针值;我在我的机器上运行时看到的垃圾来自这个指针值。实际上,如果我将 ex 3 更改为

#include <iostream>

int main(void) 
{
    char a = 'a';
    long b = 0x68676665646362l;
    std::cout << &a;
}

我得到输出

abcdefgh

当然这是一个未定义行为的例子;用另一个编译器编译,在另一个平台上运行,程序也可以按标准崩溃,打印完整的哈姆雷特文本或实现自我意识。

于 2013-08-18T15:21:09.187 回答
2

第二个和第三个示例将指针输出为字符串。但由于实际数据只是没有字符串终止符的单个字符,因此输出运算符在搜索终止符时继续输出超出实际数据的输出,因此您会得到未定义的行为。

如果要打印实际指针,则必须强制转换指针:

std::cout << static_cast<void*>(&a) << '\n';
于 2013-08-18T15:18:03.467 回答