关于c ++:“取消引用”指针是什么意思?

What does “dereferencing” a pointer mean?

请在解释中包括一个例子。


复习基本术语

通常情况下,设想一个指针包含一个数字内存地址就足够了(除非您正在编程汇编),其中1表示进程内存中的第二个字节,2表示第三个字节,3表示第四个字节,依此类推……好的。

  • 0和第一个字节发生了什么?好吧,我们稍后再讨论这个问题——见下面的空指针。
  • 要更准确地定义指针存储的内容以及内存和地址之间的关系,请参阅"有关内存地址的更多信息,以及您可能不需要知道的原因"。

当您想要访问指针指向的内存中的数据/值-地址的内容和数字索引-然后您就取消了指针的引用。好的。

不同的计算机语言有不同的符号来告诉编译器或解释器,你现在对指向的值感兴趣-我集中在C和C++之上。好的。指针方案

在c中考虑,给定一个指针,如下面的p…好的。

1
const char* p ="abc";

…四个字节的数字值用于编码字母"a"、"b"、"c",0字节表示文本数据的结尾,存储在内存的某个地方,数据的数字地址存储在p中。好的。

例如,如果字符串文本恰好位于地址0x1000,而p是32位指针位于0x2000,则内存内容将为:好的。

1
2
3
4
5
6
7
Memory Address (hex)    Variable name    Contents
1000                                     'a' == 97 (ASCII)
1001                                     'b' == 98
1002                                     'c' == 99
1003                                     0
...
2000-2003               p                1000 hex

注意,地址0x1000没有变量名/标识符,但是我们可以使用存储其地址的指针间接引用字符串文字:p。好的。取消指针引用

为了引用字符p指向,我们使用这些符号之一(同样,对于c)取消引用p:好的。

1
2
3
4
5
assert(*p == 'a');  // The first character at address p will be 'a'
assert(p[1] == 'b'); // p[1] actually dereferences a pointer created by adding
                     // p and 1 times the size of the things to which p points:
                     // In this case they're char which are 1 byte in C...
assert(*(p + 1) == 'b');  // Another notation for p[1]

您还可以在指向的数据中移动指针,并在移动时取消对它们的引用:好的。

1
2
++p;  // Increment p so it's now 0x1001
assert(*p == 'b');  // p == 0x1001 which is where the 'b' is...

如果您有一些数据可以写入,那么您可以这样做:好的。

1
2
3
4
int x = 2;
int* p_x = &x;  // Put the address of the x variable into the pointer p_x
*p_x = 4;       // Change the memory at the address in p_x to be 4
assert(x == 4); // Check x is now 4

上面,您必须在编译时知道您需要一个名为x的变量,代码要求编译器安排存储它的位置,确保地址可以通过&x使用。好的。取消引用和访问结构数据成员

在C语言中,如果有一个变量是指向具有数据成员的结构的指针,则可以使用->取消引用运算符访问这些成员:好的。

1
2
3
4
5
typedef struct X { int i_; double d_; } X;
X x;
X* p = &x;
p->d_ = 3.14159;  // Dereference and access data member x.d_
(*p).d_ *= -1;    // Another equivalent notation for accessing x.d_

多字节数据类型

要使用指针,计算机程序还需要了解所指向的数据类型-如果该数据类型需要表示多个字节,则指针通常指向数据中编号最低的字节。好的。

所以,看一个稍微复杂一点的例子:好的。

1
2
3
4
5
6
7
8
9
double sizes[] = { 10.3, 13.4, 11.2, 19.4 };
double* p = sizes;
assert(p[0] == 10.3);  // Knows to look at all the bytes in the first double value
assert(p[1] == 13.4);  // Actually looks at bytes from address p + 1 * sizeof(double)
                       // (sizeof(double) is almost always eight bytes)
assert(++p);           // Advance p by sizeof(double)
assert(*p == 13.4);    // The double at memory beginning at address p has value 13.4
*(p + 2) = 29.8;       // Change sizes[3] from 19.4 to 29.8
                       // Note: earlier ++p and + 2 here => sizes[3]

指向动态分配内存的指针

有时,在程序运行并查看向其抛出的数据之前,您不知道需要多少内存…然后可以使用malloc动态分配内存。通常的做法是将地址存储在指针中…好的。

1
2
3
4
5
int* p = malloc(sizeof(int)); // Get some memory somewhere...
*p = 10;            // Dereference the pointer to the memory, then write a value in
fn(*p);             // Call a function, passing it the value at address p
(*p) += 3;          // Change the value, adding 3 to it
free(p);            // Release the memory back to the heap allocation library

在C++中,内存分配通常是用EDCOX1×1×操作符来完成的,并且用EDCOX1 2来分配:好的。

1
2
3
4
5
6
7
8
int* p = new int(10); // Memory for one int with initial value 10
delete p;

p = new int[10];      // Memory for ten ints with unspecified initial value
delete[] p;

p = new int[10]();    // Memory for ten ints that are value initialised (to 0)
delete[] p;

请参阅下面的C++智能指针。好的。丢失和泄漏地址

通常,指针可能是内存中存在某些数据或缓冲区的唯一指示。如果需要继续使用该数据/缓冲区,或者能够调用free()delete以避免内存泄漏,那么程序员必须操作指针的副本…好的。

1
2
3
4
5
6
7
8
9
10
const char* p = asprintf("name: %s", name);  // Common but non-Standard printf-on-heap

// Replace non-printable characters with underscores....
for (const char* q = p; *q; ++q)
    if (!isprint(*q))
        *q = '_';

printf("%s
"
, p); // Only q was modified
free(p);

…或小心安排任何变化的逆转…好的。

1
2
3
4
const size_t n = ...;
p += n;
...
p -= n;  // Restore earlier value...

C++智能指针

在C++中,最好使用智能指针对象来存储和管理指针,在智能指针析构函数运行时自动释放它们。自从C++ 11以来,标准库提供了两个EDCOX1,5,当有一个被分配对象的所有者时…好的。

1
2
3
4
5
{
    std::unique_ptr<T> p{new T(42,"meaning")};
    call_a_function(p);
    // The function above might throw, so delete here is unreliable, but...
} // p's destructor's guaranteed to run"here", calling delete

…和shared_ptr的股份所有权(使用参考计数法)好的。

1
2
3
4
{
    std::shared_ptr<T> p(new T(3.14,"pi"));
    number_storage.may_add(p); // Might copy p into its container
} // p's destructor will only delete the T if number_storage didn't copy

空指针

在C中,EDCOX1,7,EDCOX1,8,-另外,在C++中,EDCOX1,9,-可以用来指示指针当前不保存变量的内存地址,不应该在指针算术中被撤销或使用。例如:好的。

1
2
3
4
5
6
7
8
const char* p_filename = NULL; // Or"= 0", or"= nullptr" in C++
char c;
while ((c = getopt(argc, argv,"f:")) != EOF)
    switch (c) {
      case f: p_filename = optarg; break;
    }
if (p_filename)  // Only NULL converts to false
    ...   // Only get here if -f flag specified

在C和C++中,正如内建的数字类型不一定默认为EDCOX1〔8〕,也不必EDCOX1对EDCOX1〔12〕11〕,指针不总是设置为EDCOX1〔7〕。当它们是EDOCX1、14个变量或(C++)静态对象或它们的基元的直接或间接成员变量时,所有这些都被设置为0 /假/空,或者进行零初始化(例如EDCOX1×15)和EDCOX1〔16〕在T的成员上执行零点初始化,包括指针,而EDCOX1〔17〕不成立。好的。

此外,当您将0NULLnullptr分配给指针时,指针中的位不一定全部重置:指针在硬件级别可能不包含"0",或者在虚拟地址空间中引用地址0。如果编译器有理由的话,它可以在那里存储其他东西,但是不管它做什么——如果您来比较指向0NULLnullptr的指针或分配给其中任何一个指针的另一个指针,比较必须按预期工作。因此,在编译器级别的源代码下面,"NULL"在C语言和C++语言中可能有点"神奇"。好的。关于内存地址的更多信息,以及为什么您可能不需要知道

更严格地说,初始化指针存储一个位模式,标识NULL或(通常是虚拟的)内存地址。好的。

简单的情况是,这是对进程的整个虚拟地址空间的一个数字偏移;在更复杂的情况下,指针可能是相对于某些特定的内存区域的,CPU可以根据CPU"段"寄存器或以位模式编码的段ID的某种方式进行选择,和/或根据MAC查找不同的位置。使用地址对指令进行编码。好的。

例如,正确初始化以指向int变量的int*可能在转换为float*之后访问"gpu"内存中与int变量非常不同的值,然后一旦转换为函数指针,则可能指代保存该函数的机器操作码的不同内存。好的。

像C和C++这样的3GL编程语言倾向于隐藏这种复杂性,例如:好的。

  • 如果编译器给你一个指向变量或函数的指针,你可以自由地取消引用它(只要变量没有同时被破坏/释放),这是编译器的问题,例如某个特定的CPU寄存器需要预先恢复,还是使用了一个不同的机器代码指令好的。

  • 如果您得到一个指向数组中某个元素的指针,您可以使用指针算法移动数组中的任何其他位置,或者甚至形成一个地址,该地址是一个超过数组末尾的地址,与数组中元素的其他指针进行比较是合法的(或者类似地,该地址也是通过指针算法移动到超过结束值的同一个地址);同样,在C和C++,这取决于编译器来确保这个"只是工作"。好的。

  • 特定的操作系统功能,例如共享内存映射,可能会给您提供指针,它们将在对它们有意义的地址范围内"正常工作"。好的。

  • 尝试将法律指针移到这些边界之外,或者将任意数字投给指针,或者使用指针转换为无关类型,通常具有未定义的行为,因此在更高级别的库和应用程序中应该避免,但是OSES、设备驱动程序等代码可能需要依赖于C或C++未定义的行为,即NE。无垂直,由其特定硬件定义良好。好的。

好啊。


取消对指针的引用意味着获取存储在指针指向的内存位置中的值。运算符*用于执行此操作,称为解引用运算符。

1
2
3
4
5
6
7
8
9
10
11
int a = 10;
int* ptr = &a;

printf("%d", *ptr); // With *ptr I'm dereferencing the pointer.
                    // Which means, I am asking the value pointed at by the pointer.
                    // ptr is pointing to the location in memory of the variable a.
                    // In a's location, we have 10. So, dereferencing gives this value.

// Since we have indirect control over a's location, we can modify its content using the pointer. This is an indirect way to access a.

 *ptr = 20;         // Now a's content is no longer 10, and has been modified to 20.


指针是对值的"引用"。就像图书馆的电话号码是对一本书的引用。"取消对"呼叫号码的引用实际上是在浏览和检索那本书。

1
2
3
4
5
6
7
8
int a=4 ;
int *pA = &a ;
printf("The REFERENCE/call number for the variable `a` is %p
"
, pA ) ;

// The * causes pA to DEREFERENCE...  `a` via"callnumber" `pA`.
printf("%d
"
, *pA ) ; // prints 4..

如果书不在那里,图书管理员就开始叫喊,关闭图书馆,并且有几个人准备调查一个人找不到书的原因。


简单来说,取消引用意味着从指针指向的某个内存位置访问值。


指针基础的代码和解释:

The dereference operation starts at
the pointer and follows its arrow over
to access its pointee. The goal may be
to look at the pointee state or to
change the pointee state. The
dereference operation on a pointer
only works if the pointer has a
pointee -- the pointee must be
allocated and the pointer must be set
to point to it. The most common error
in pointer code is forgetting to set
up the pointee. The most common
runtime crash because of that error in
the code is a failed dereference
operation. In Java the incorrect
dereference will be flagged politely
by the runtime system. In compiled
languages such as C, C++, and Pascal,
the incorrect dereference will
sometimes crash, and other times
corrupt memory in some subtle, random
way. Pointer bugs in compiled
languages can be difficult to track
down for this reason.

1
2
3
4
5
6
void main() {  
    int*    x;  // Allocate the pointer x
    x = malloc(sizeof(int));    // Allocate an int pointee,
                            // and set x to point to it
    *x = 42;    // Dereference x to store 42 in its pointee  
}


我认为以前所有的答案都是错误的,因为它们声明取消引用意味着访问实际值。维基百科给出了正确的定义:https://en.wikipedia.org/wiki/dereference_operator网站

It operates on a pointer variable, and returns an l-value equivalent to the value at the pointer address. This is called"dereferencing" the pointer.

也就是说,我们可以不必再引用指针访问它指向的值。例如:

1
2
char *p = NULL;
*p;

我们在不访问空指针的价值。或者我们可以这样做:

1
2
p1 = &(*p);
sz = sizeof(*p);

同样,取消引用,但从不访问值。这样的代码不会崩溃:当您通过指针无效。然而,不幸的是,根据标准,取消对无效指针的引用是未定义的行为(除了少数例外),即使你不尝试触摸实际数据。

简而言之:取消引用指针意味着应用取消对它的引用运算符。那个接线员只是返回一个L值供您将来使用。