【问题标题】:cout with pointers c++cout 指针 c++
【发布时间】:2023-04-03 21:36:01
【问题描述】:

我不明白为什么cout 在这段代码中不起作用:

#include<iostream>
using namespace std;

int main() {
    int v = 65;
    int* q = &v;
    char** o = (char**)&q;
    cout <<  o << endl;  // output: 012FFCAC
    cout <<  *o << endl; // output: A
    cout << **o << endl; // output: A
    printf("%c",*o);     // cause an error
    printf("%p",*o);    // works and the output=&v

cout 在此代码中的其他部分不起作用

#include<iostream>
using namespace std;

int main() {
    char v = 65;
    cout <<  &v << endl;  // output: A╠╠╠╠▀?╞«4°O 

【问题讨论】:

  • 你的编译器应该给你一个警告。如果不是,请调整您的警告选项。
  • -克里斯没有警告
  • 运算符 &lt;&lt; 用于将 const char * 流式传输到输出流 假设指针指向以 nul 结尾的字符串(例如字符串文字)的第一个字符 - 即带有 char 的数组一个 nul(零)终止符,标记结束。传递&amp;v 意味着指针不是以nul 结尾的字符串的第一个字符,因为不能保证v 之后的内存内容。因此行为是未定义的。
  • operator&lt;&lt;() 的重载支持单个char 的输出,另一个支持char * 的输出(假设char * 指向什么,如我在之前的评论中提到过)。通过一些它不期望的东西,并且行为是未定义的。同样,您的示例中的printf("%c", *o) 具有未定义的行为,因为*ochar *,而%c 告诉printf() char(不是char *)已通过。
  • 不需要特殊的重载。如果你想要地址,你可以将&amp;v 转换为不同的类型,通常是void *,这不会做字符串的事情。

标签: c++ pointers


【解决方案1】:

因为一个 int (通常)是 4 个字节 65 将非常整齐地放入第一个字节,而分配给 int 的其余内存将是 0 这个字节模式恰好与如何匹配非常接近strings 存储在内存中。

因此,当通过char* 访问内存时,即使大多数打印格式不正确,它也会在大多数情况下打印A

int v = 65;  // Byte pattern on most machines [65,0,0,0] 
int* q = &v; 
char** o = (char**)&q; // *o now points to [65,0,0,0] ==> ['A','\0','\0','\0'] ==> "A"
std::cout <<  o << std::endl;  
    // input:      char** 
    // printed as: pointer 
    // result:     012FFCAC

std::cout <<  *o << std::endl;  // Undefined Behaviour
    // input:      char*
    // printed as: null terminated string
    // result:     "A"

std::cout <<  **o << std::endl; // Undefined Behaviour 
    // input:      char
    // printed as: single character
    // result:     'A'

printf("%c",*o);    // %c expects a [char] type but is given [pointer to char]      ERROR
printf("%p",*o);    // %p expects a [pointer] type and is given a [pointer to char] OK

由于char(通常)是 1 个字节,因此没有空终端,一旦开始打印就停止打印,它会继续打印内存中的任何内容,直到遇到 0 或访问冲突

char v = 65;
std::cout << &v << std::endl;  // &v is not a well-formed null terminated string: Undefined Behaviour
    // input:      char*
    // printed as: null terminated string
    // result:     "A<whatever other data is around v in memory>"

【讨论】:

  • char** o = (char**)&q; // *o 现在指向 [65,0,0,0] ==> ['A','\0','\0','0'] ==> "A" 这里我猜你需要将 ['A','\0','\0','0'] 最后一个 '0' 更改为 '\0' 对吗?我想问你(未定义的行为)是否意味着没有人知道它可能有效,也可能无效? @Fiskmans
  • 是的,谢谢,应该是 \0
  • 未定义的行为(UB)只是意味着它在标准中没有很好地定义。在许多情况下,它会按预期运行,但编译器供应商可以自行决定更改工作方式(有意或无意),您将成为 SOL。这也意味着您的代码可能会根据您编译它的目的而有所不同,例如,如果您为 little-endian 机器构建代码,则 65 将在内存中以相反的方式布局 ['\0', '\0','\0','65'] 你的代码会打印出完全不同的东西
  • 我从您的评论中了解到,UB 意味着代码(程序)总是会运行(将工作),但没有人知道它将如何工作(将运行)它可能会运行(工作)代码编写者期望并且可能运行(工作),但不像代码编写者期望的那样运行这是你的意思吗? @Fiskmans
  • 差不多,但不能保证程序会真正运行。它通常并不算太糟糕,但允许兼容的编译器做任何它想做的事情,从“你期望它做的事情”到“​​删除重要文件,砖设备或打电话给白宫”。它通常不是那么糟糕,但故意编写 UB 代码是一种非常糟糕的做法
猜你喜欢
  • 2021-11-28
  • 1970-01-01
  • 2011-08-30
  • 2012-09-21
  • 2021-07-28
  • 2016-08-25
  • 1970-01-01
  • 2011-01-05
相关资源
最近更新 更多