空指针的内存位置
Memory location of null pointer
在阅读了很多关于空指针的问题之后,我仍然对空指针的内存分配感到困惑。
如果我输入以下代码-
int a=22;
int *p=&a;//now p is pointing towards a
std::cout<<*p;//outputs 22
std::cout<<p;//outputs memory address of object a;
int *n=nullptr;// pointer n is initialized to null
std::cout<<n;
编译完这段代码后,指针n输出常量0,如果我尝试这样做,
std::cout<<*n;
这行代码是编译器编译的,但是无法执行,这段代码是怎么了,应该打印这个指针的内存位置
std::cout<<p;
输出指针在内存中的位置或对象在内存中的位置。因为许多或所有这些答案已经在前面的问题中得到了回答,但不知何故我无法理解,因为我是c++的初学者。
nullptr
指针不指向任何东西。它不包含有效地址,而是包含"非地址"。它是概念性的,你不应该担心它的价值。
唯一重要的是你不能解引用一个nullptr
指针,因为这会导致未定义的行为,这就是为什么你的程序在运行时失败(std::cout<<*n
)
std::cout<<p;
在变量p
的一般输出值中,该值的含义取决于p's
类型。在你的例子中,type or p是指向int (int *)的指针,所以它的值是int的地址。因为指针本身是一个左值,你可以得到它的地址,所以如果你想看到你的指针n
在内存中的位置,只要输出它的地址:
std::cout << &n << std::endl;
正如许多其他答案所述,不解引用空指针,因为它会导致UB。所以:
std::cout << n << std::endl; // value of pointer n, ie address, in your case 0
std::cout << &n << std::endl; // address of pointer n, will be not 0
std::cout << *n << std::endl; // undefined behavior, you try to dereference nullptr
如果你想看到nullptr
本身的地址,你不能——它是一个常量,不是左值,也没有地址:
std::cout << &nullptr << std::endl; // compile error, nullptr is not lvalue
编译时:
std::cout << *n;
编译器通常会生成如下代码:
mov rax, qword ptr [rbp - 0x40]
mov esi, dword ptr [rax]
call cout
第一行查找指针的地址(rdp - 0x40)并将其存储在CPU寄存器RAX中。在本例中,nullptr的地址为0。RAX现在包含0。
第二行尝试从RAX指定的位置(0)读取内存。在典型的计算机设置中,内存位置0是受保护的(它不是有效的数据内存位置)。这会导致无效的操作并导致崩溃*。
它永远不会到达第三行。
*然而,这并不是在所有情况下都是正确的:在没有操作系统的微控制器上,这可能成功地解引用并读取内存位置0的值。然而*nullptr并不是表达这种意图的好方法!请参阅http://c-faq.com/null/machexamp.html了解更多讨论。如果你想要nullptr的全部细节:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
nullptr
是一个特殊的值,没有一个有效的指针可以得到这个值。在许多系统中,该值等于数字0,但是不是将nullptr
视为数字值是个好主意。
要理解nullptr
的含义,首先应该考虑指针的含义:它是一个指向其他东西的变量,也可能根本不指向任何东西。你需要能够区分"我的指针指向某物"answers"我的指针什么都没有指向"的状态。这就是nullptr
的由来:如果一个指针等于nullptr
,你知道它引用了"什么都没有"。
注意:解引用nullptr
(即对其应用一元星号操作符)是未定义的行为。它可能会崩溃,或者打印一些值,但这将是一个"垃圾值"。
解除空指针的引用是未定义的行为,所以任何事情都可能发生。但是,空指针仍然必须在内存中占有一席之地。所以你看到的就是这样。通常编译器实现一个空指针,因为它的值都是0。
仅仅因为这是一句黄金引语,以下是Scott Meyer在他的《Effective c++ 2nd edition》一书中对UD行为的看法。
"然而,这里有一些非常麻烦的事情。程序的行为是未定义的——你无法知道会发生什么发生……这意味着编译器可以生成代码来做它们想做的任何事情比如:重新格式化你的磁盘,给你的老板发有性暗示的电子邮件,传真源代码给你的竞争对手,等等。"
对空指针解引用是未定义的行为。编译器选择或无意中发生的任何行为都是有效的。
在其他地方更改程序也可能改变该代码行的行为。
我怀疑您的困惑是由于这里涉及到两个内存位置。
在此代码中:
int *n=nullptr;// pointer n is initialized to null
有一个变量n
,该变量占用内存空间。你可以取n
的地址并证明给自己看:
std::cout << &n << "n";
你会看到n
的地址是合法的。如,不是NULL。
n
恰好是指向- int
的类型,它指向的东西是NULL。这意味着它根本不指向任何东西;它处于不能解引用的状态
但是"解引用它"正是你在这里所做的:
std::cout<<*n;
n
是有效的,但它指向的东西是无效的。
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 内存所有位置 wxWidgets
- 为什么字符串的 move() 会改变内存中底层数据的位置?
- 如何在不等待检索的情况下获取C++中的内存位置?
- 内存中类位置的成员是否取决于类成员在类定义中的位置?
- 向量的内存位置不连续
- 如何根据C++在同一内存位置重新初始化 C# 中的对象(还是自动完成)?
- 常量引用的内存位置
- C++强制变量到一个固定的内存位置
- 为什么未初始化的内存位置的值给出 -842150451 的值?
- 为什么存储在内存位置的值会发生变化?
- 在特定内存位置构造 c++ 对象
- 如果不初始化结构中的向量,它会自动为空还是具有随机内存位置的值?
- 如何识别内存泄漏的位置
- 内存位置出现Microsoft C++异常:std::out_of_range
- 函数,返回变量c++占用的内存位置的大小
- 在尝试使用CUDA分配内存时,我遇到了访问冲突写入位置错误
- delete如何知道对象在内存中的起始位置
- 无法在 Opencv 中显示图像导致内存位置
- 如何修复<程序名称>中的"<内存位置>未处理的异常。Visual Studio 2017 中的访问冲突写入位置<内存位置>"