【问题标题】:How does incrementing memory address affects pointer递增内存地址如何影响指针
【发布时间】:2019-10-29 16:39:26
【问题描述】:

我正在寻找关于增加地址如何影响指针的解释。

我了解了 C 指针的工作原理以及如何通过考虑指针类型来完成指针的递增。还是没看懂下面的案例

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(&a+1);
    printf("%d\n%d\n", *(a+1), *(p-1));
    return 0;
}

我期待这条线

int *p = (int*)(&a+1);

使p指向数组a后面的地址,因此我期望输出:

2 

就是a[1]

但输出是 unknown_number - 因为我不知道哪个 int 比 (&a+1) 落后 4 个字节@

而实际结果是:

2

5

为什么p 似乎直接指向了位于a 之后的内存?

我的困惑的根源是什么?

【问题讨论】:

  • 删除&
  • 另一个例子表明强制转换在 C 中几乎没有帮助。为什么强制转换?它消除了编译器给你的警告/错误。不要怀疑....

标签: c pointers memory memory-management pointer-arithmetic


【解决方案1】:

所以在这个例子中&a 的类型是int(*)[5]。当您向其添加 1 时,它实际上添加了 sizeof(int[5]) - 因为这就是指针算法的工作原理,添加偏移量会增加指向的类型的大小乘以偏移量。这就是你如何让p 成为a 的最后一个元素,然后将其转换为int*,所以现在你有一个指针指向一个整数,其地址是a 的最后一个元素之后的一个地址.如此有效,从中减去 1 即可得到a 的最后一个元素。

【讨论】:

  • 我困惑的关键是我不完全理解为什么 &a 是 int[5]* 类型,&a 不只是一个地址吗?语言如何“知道”它是 int[5]*?
  • @limitless:编译器知道a 有5 个元素,就像它知道元素是ints:你告诉它的。所以它将&a + 1编译成机器码,将5*sizeof(int)添加到a的地址。 (编译器也知道suzeof(int) 是什么,因此它可以使用该表达式的实际值。)这些都不要求信息在运行时可用,而且可能不是。
  • 没有类型int [5]*,是语法错误。你的意思是int (*)[5]
  • @AnttiHaapala 感谢更正,应该刚刚写了指向 int[5] 的指针:D
【解决方案2】:

您可以将数组 a 作为指向 int int * 的指针进行操作。但&a 不一样,它是一个指向 5 个整数数组的指针:&a + 1 会将 5 个整数的大小添加到指针中。

只需在 a 加 1 之前删除 &,它就会按预期工作:

#include <stdio.h>

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(a+1); // & removed
    printf("%d %d\n", *(a+1), *(p-1));
    return 0;
}

【讨论】:

  • 它与评论有何不同?
【解决方案3】:

两个基本概念:

  • 除非它是sizeof 或一元&amp; 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 类型“T 的 N 元素数组”将被转换(“衰减”)为“指向T”的指针类型的表达式,表达式的值将是数组第一个元素的地址。

  • 将 1 加到“指向T 的指针”类型的表达式会产生紧跟当前对象的T 类型对象的地址。 IOW,如果p 指向一个4 字节的intp+1 则指向紧随其后的int。如果p 指向int 的5 元素数组,则p+1 指向紧随其后的int 的下一个5 元素数组。这就是数组索引的工作原理——下标操作a[i] 定义为*(a + i)。给定一个起始地址a(指针表达式或衰减为指针的数组表达式),找到该地址之后的i'th 对象的地址并取消引用结果。

所以,如果你有声明

int a[] = {1, 2, 3, 4, 5};

那么以下是正确的:

  • 表达式a 的类型为“int 的 5 元素数组”(int [5]) - 如果表达式不是 sizeof 的操作数或一元&amp; 运算符,它“衰减”到键入“指向int”的指针(int *),其值为数组第一个元素的地址(&amp;a[0])。

  • 表达式 *(a + 1)a[1] 相同,并计算为数组中的第二个对象 (2)。

  • 表达式&amp;a + 1 的类型为int (*)[5],并在a 之后产生int 的5 元素数组的起始地址。此表达式的类型转换为int * 并分配给p

  • 表达式 p 的类型为 int * - 从中​​减去 1 会得到紧接在 p 之前的 int 对象的地址,它恰好是 a 的最后一个元素。

图形化:

   +–––+
a: | 1 |
   +–––+
   | 2 | <–– a + 1
   +–––+
   | 3 |
   +–––+
   | 4 |
   +–––+
   | 5 | <–– p - 1
   +–––+
   | ? | <–– p (&a + 1)
   +–––+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-23
    • 2012-10-19
    • 1970-01-01
    • 2012-01-02
    • 2019-03-27
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多