在阅读了很多关于空指针的问题之后,我仍然对空指针中的内存分配感到困惑。
如果我输入以下代码 -
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 ++的初学者。
答案 0 :(得分:4)
nullptr
指针并不指向任何东西。它不包含有效地址,但是包含非地址&#34;。从概念上讲,你不应该担心它的价值。
唯一重要的是你不能取消引用nullptr
指针,因为这会导致未定义的行为,这就是你的程序在运行时失败的原因(std::cout<<*n
)
答案 1 :(得分:3)
std::cout<<p;
通常输出变量p
的值,该值的含义取决于p's
类型。在你的情况下,type或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
答案 2 :(得分:2)
nullptr
是一个特殊值,选择方式是没有有效指针可以获得此值。在许多系统上,该值等于数字零,但根据其数值值来考虑nullptr
是个好主意。
要理解nullptr
的含义,首先要考虑指针的含义:它是一个引用其他东西的变量,它也可能根本就没有任何东西。你需要能够区分状态&#34;我的指针指的是某些东西&#34;来自国家&#34;我的指针根本没有提及&#34;。这是nullptr
的来源:如果指针等于nullptr
,你知道它引用了#34;什么都没有&#34;。
注意:解除引用nullptr
(即对其应用一元星号运算符)是未定义的行为。它可能会崩溃,或者它可能会打印一些值,但它会是一个垃圾值&#34;。
答案 3 :(得分:2)
取消引用空指针是未定义的行为,因此anything at all can happen。但是,空指针仍然必须在内存中占有一席之地。所以你所看到的只是那个。通常编译器实现空指针,因为它的值全为0。
仅仅因为它是一个金色的引用,这就是Scott Meyer关于UD行为的说法,来自他的着作“有效的C ++第二版”。
“然而,这里有一些令人不安的事情。你的节目是 行为未定义 - 你无法知道会发生什么 发生......这意味着编译器可能会生成代码来执行任何操作 喜欢:重新格式化你的磁盘,发送暗示性的电子邮件给你的老板,传真 无论如何,你的竞争对手的源代码。“
答案 4 :(得分:1)
取消引用空指针是未定义的行为。编译器选择或无意中发生的任何行为都是有效的。
在其他地方更改程序也可能会改变此代码行的行为。
答案 5 :(得分:1)
编译时:
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
答案 6 :(得分:0)
我怀疑你的困惑是围绕这里涉及两个内存位置的事实。
在此代码中:
int *n=nullptr;// pointer n is initialized to null
有一个变量n
,该变量占用内存空间。您可以使用n
的地址并自行证明:
std::cout << &n << "\n";
你会发现n
的地址是合法的。如同,不是NULL。
n
恰好是指向int
的指针类型,它指向的是NULL。这意味着它根本不指向任何东西;它处于一个你无法取消引用它的状态。
但是“取消引用它”正是你在这里所做的:
std::cout<<*n;
n
有效,但它所指的不是。这就是你的程序形成不良的原因。