数组中的指针。它在内存中如何工作 "physically"?

Pointer in arrays. How does it work "physically" in memory?

我一直对指针感到疑惑,但找不到详细解释它们的来源。

例如。给定一个数组 int a[3] 有一个指针指向4个位置? 它以 *[a+0] 开头并指向 a? 那么它接下来做什么呢? int最小16位,所以需要读取2个字节,但是每个字节都有一个地址。

是否意味着对于 a[0] 指针指向起始地址,然后程序从给定地址开始读取 sizeof(int) 个字节?

接下来它会做什么?它会停止阅读,给出结果并 对于 a[1],它会指向 &a+1*sizeof(int) 的地址吗? 它会从 (&a+2(因为 2 代表已经读取了 2 个字节的地址)) 的地址开始读取,开始读取,所以它会读取另外 2 个字节,然后继续读取?

我不是很理解这些概念。

PS:字符串由 1 字节元素的无符号字符组成。 您提到的 post 没有解释大于 1 个字节的元素会发生什么。它也没有准确解释程序在 "here is a string the program reads from memory" 旁边做了什么。我认为我是对的,但你提到的标题与我问的相去甚远。 (因为已经有人写过了,一个地址代表一个字节)

  54   55   56   57   58   59   60   61   62   63   64   65   66   67   68   69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|----|----|----|----|----|----|    |    |    |    |    |    |    |    |    |    |
0----+----01---+----12---+----2----+----+----+----+----+----+----+----+----+----+

我特意问过 int a[2] 表示指针在前: 指向内存地址(54),程序从后面的2个地址(54到54,因为int占用2个字节)读取数据,然后指针指向地址54+2,程序从地址范围<56,57>开始读取。再一次,指针指向起始范围58,程序读取地址<58,59>

这个逻辑对吗?它不是以 NULL 结尾的字符串。 我对字符串的猜测是程序将按字节地址访问内存字节地址并读取值直到找到 NULL。

数组不是字符串。

考虑

int a[3] = {};
int b[300] = {};

这 2 个数组是 "similar",因为它们包含 int 的值,并且在以下两个主要方面有所不同:

  1. 它们是不同的 "size" - 即它们 指向 的内存被保留,每个内存的数量不同。第一个数组指向一个内存,该内存保留用于保存 至少 3 int 个值。然而,这是最小分配的内存(在这种情况下 - 在堆栈上,因此很可能它也是为其分配的精确内存量还有)
  2. 它们指向内存中的不同地址(再次 - 在这种情况下,它们都分配在堆栈上,但它仍然是 RAM)

您可以轻松获取任一数组的第一个元素的地址:

int * p = a;
p = &a[0]; // same as above
p = b; // now p points to the first element of the second array

当您执行 索引操作时 编译器所做的是:它获取第一个元素的地址并将其递增等于 index 乘以每个元素的大小(当然,如果由于对齐而没有填充)。本质上编译器是这样做的:

b[1] = 1;
*(p+1) = 1; // same as above
uint8_t * c = reinterpret_cast<uint8_t*>(p); // WARNING! Explanation follows

最后一行将导致编译器重新解释指针,"the same"地址算法"suddenly"的工作方式也不同:

c[1] = 1; // this is NOT the same as b[1] = 1

在这种情况下,编译器只会 "move" 指针 8 位(不是 16 位或 32 位,具体取决于您的平台 sizeof(int))并在中间结束 数组 b 的第一个 int 元素。当然 可以 有用(尤其是在直接处理硬件时)但是 super-duper-puper non-portable 并且您应该始终避免这样做!

诚然,这不是一个全面的答案,但我的目的不是提供一个,因为这个话题非常广泛,而且网络上有大量资源可以为您提供关于这个主题的更多细节