“指针指向另一个存储位置”是什么意思?

时间:2020-06-02 17:32:13

标签: c pointers memory-address

我知道一个指针变量存储了另一个变量的内存地址。 “指针指向另一个内存位置”是什么意思?

2 个答案:

答案 0 :(得分:0)

从根本上讲,variable是名称与内存中位置之间的关联。它可能比其他语言更复杂,并且其他信息通常与变量(例如类型)相关联,但这与此处无关。

指针变量是一个变量(一个引用内存某些区域的名称),但是该内存区域中有什么? pointer本身是什么?好吧,这是一个内存地址,一种引用另一个内存位置的方式。我们不是说“指针具有价值这个另一个存储位置”,而是说指针引用指向另一个存储位置。< / p>

我们可能有其他存储位置的名称。那将使其成为变量。因此,我们也说指针引用指向该另一个变量。

下面,我们有一个指向变量p的指针i

int i = 1000;
int *p = &i;

我们可能有以下记忆:

p at addr 0x1122       |      ⋮       |
i at addr 0x3344       +--------------+
                       |       0x3344 | 0x1122
                       +--------------+
                       |      ⋮       |
                       +--------------+
                       |         1000 | 0x3344
                       +--------------+
                       |      ⋮       |

那么以下两个语句有什么区别?

int *q = p;
int j = *p;

首先,我们复制指针本身,即内存地址。

第二,我们间接访问i。我们告诉C指针 dereference ,这意味着访问指针所指向的指针。这是i

我们可能有以下记忆:

p at addr 0x1122       |      ⋮       |
i at addr 0x3344       +--------------+
q at addr 0x5566       |       0x3344 | 0x1122
j at addr 0x7788       +--------------+
                       |      ⋮       |
                       +--------------+
                       |         1000 | 0x3344
                       +--------------+
                       |      ⋮       |
                       +--------------+
                       |       0x3344 | 0x5566
                       +--------------+
                       |      ⋮       |
                       +--------------+
                       |         1000 | 0x7788
                       +--------------+
                       |      ⋮       |

如果您更改*p*qij中的一个会怎样?我让你进行假设和实验:)

答案 1 :(得分:0)

它指向另一个存储位置,就像您最近收到的明信片上的邮寄地址指向您的家一样。指针包含一个存储单元的地址。邮政地址包含实际位置的地址-无论是建筑物,公寓还是邮政信箱……“指向”因此表示“是指……的位置”。指针和邮政地址都是如此。

并非必须将指针指向另一个存储位置。的确,现实世界中使用的绝大多数指针确实指向其他地方。也就是说,99.9...%指针在世界上在任何给定时间都存在,小数点后还有15个9。至少,非常。

但是指针当然也可以指向自身。有时,如果您只想将指针放在某个地方并了解该“某处”在哪里,就会很方便。例如,在大多数C和C ++实现中,以下简短程序将在运行时打印指针变量所在的堆栈地址(是的,这些实现不必将变量存储在堆栈上,但是在大多数实际情况下,确实是一个堆栈地址):

#include <stdio.h>

int main() {
  void *pointer = &pointer;
  printf("The variable \"%s\" is stored on stack at address %p\n", "pointer", &pointer);
}

例如,我得到以下输出:

The variable "pointer" is stored on stack at address 0x7fff2350e9f8

指针也可能指向存储位置。空指针就是一个例子:

// Conformant C and C++
int *nullPointer1 = NULL; // Idiomatic C
int *nullPointer2 = 0;
// Conformant C++
int *nullPointer3 = nullptr; // Idiomatic C++
int *nullPointer4 = {}; // Idiomatic C++
std::unique_ptr<int> nullPointer5; // This is really C++ - raw pointers should be used only when truly needed, in library code etc.

这样的指针是可以的,但是唯一有效的用法是检查它们是否确实为空。无法取消引用它们-我的意思是,您可以取消引用它们,但这是未定义的行为,现代编译器将代码中未定义的行为视为删除此类代码的许可。也就是说,如果取消引用空指针,并且编译器可以证明情况始终如此,则可以删除进行这种取消引用的代码。示例(gcc 10.1 x64,-O3):

int main() {
  int *pointer = 0;
  int b = *pointer;
}

// produces same assembly output as
int main() { return 0; }

它会变得更好。这段代码:

int main() {
   int *pointer = 0;
   *pointer = 5;
}

编译时,第二行就像您写了*pointer = 0一样被修改,并且在赋值之后紧跟着ub2“指令”,该指令触发了未定义的指令异常。换句话说:如果在映射第0个内存页的进程中运行了此操作,则即使在地址5加载0也是有效的操作,它也会失败!相反,它将在地址0上加载0,然后由于异常而失败。