【问题标题】:subtracting two addresses giving wrong output减去两个地址给出错误的输出
【发布时间】:2017-06-12 11:33:24
【问题描述】:
int main()
{
    int x = 4;
    int *p = &x;
    int *k = p++;
    int r = p - k;
    printf("%d %d %d", p,k,p-k);
    getch();
}

输出:

2752116 2752112 1

为什么不4

而且我不能使用p+k 或除- 之外的任何其他运算符(减法)。

【问题讨论】:

  • 先试试这个:int r = (int)((char *)p - (char *)k)。让我们知道结果。稍后我们将讨论结果。
  • 您的代码调用了未定义的行为。 %d 需要 int 参数,您传递指针和 ptrdiff_t。并且指向不同不同数组的指针(单个对象被视为 1 元素数组)可能不会被减去(分别是没有意义的差异)。您应该阅读一本好的 C 书籍中的回合指针。你认为两个指针的总和应该产生什么?

标签: c pointers pointer-arithmetic


【解决方案1】:

首先,您必须为提供的格式说明符使用正确的参数类型,提供不匹配的参数类型会导致undefined behavior

  • 您必须使用%p 格式说明符并将参数转换为void * 以打印地址(指针)

  • 要打印指针减法的结果,您应该使用%td,因为结果的类型是ptrdiff_t


也就是说,关于减法的结果1,指针算术尊重数据类型。引用C11,第 §6.5.6 章,(强调我的

当两个指针相减时,都指向同一个数组对象的元素, 或者数组对象的最后一个元素; 结果是 两个数组元素的下标。结果的大小是实现定义的, 其类型(有符号整数类型)为ptrdiff_t,在<stddef.h> 标头中定义。 [....] 如果表达式 PQ 分别指向 i-th 和 j-th 元素 一个数组对象,表达式(P)-(Q) 具有值i−j,前提是该值适合ptrdiff_t 类型的对象。 [....]

因此,在您的情况下,pk 的索引是分开的一个元素,即|i-J| == 1,因此是结果。


最后,你不能相加(或相乘或相除)两个指针,因为那是没有意义的。指针是内存位置,从逻辑上讲,您无法理解添加两个内存位置。只有减法才有意义,才能找到两个数组成员/元素之间的相关距离。

相关约束,来自C11,第 §6.5.6 章,加法运算符,

对于加法,两个操作数都应具有算术类型,或者一个操作数应为 指向完整对象类型的指针,另一个应具有整数类型。 (递增是 相当于加1。)

【讨论】:

    【解决方案2】:

    您得到的是两个元素的下标之间的差异。
    C11-6.5.6p9:

    当两个指针相减时,两个指针都指向同一个数组对象的元素,或者指向数组对象最后一个元素的元素; 结果是两个数组元素的下标之差

    还要注意语句

     printf("%d %d %d", p,k,p-k);  
    

    应该是

    printf("%p %p %ld\n", (void*)p,(void*)k, p-k);
    

    【讨论】:

      【解决方案3】:

      如果你的变量是指针类型,那么每次对指针的计算都是通过乘以指针类型大小来完成的。

      例如:

      //Lets assume char is 1 byte, int is 4 bytes long.
      // sizeof(*cp) = 4, sizeof(*ip) = 4;
      char *cp = (char *)10;  //Char itself is 1 byte
      int *ip = (int *)10;
      cp++;          //Increase pointer, let us point to the next char location
      ip++;          //Increase pointer, let us point to the next int location
      
      printf("Char: %p\r\n", (void *)cp); //Prints 11
      printf("Int: %p\r\n", (void *)ip); //Prints 14
      

      第一种情况打印11,而第二种情况打印14。那是因为下一个 char 元素是 1 个字节,而下一个 int 元素是 4 个字节。

      如果您有 2 个相同类型的指针(例如,int *,就像您一样),那么如果一个指向 14,另一个指向 10,则两者之间用于 1 int 内存,减法得到 @987654328 @。

      如果你想得到你的结果4,那么在计算之前将指针转换为char *,因为sizeof(char)总是1,这意味着你在1014之间有4元素你会得到结果4

      希望对你有帮助。

      【讨论】:

      • 我同意第一个,但如果uint32_t 和指针长度相同,第二个它将起作用。否则,我再次同意 void * @DavidBowling 但我添加了这个 sizeof(*cp) = 4, sizeof(*ip) = 4; 所以我们假设 int * 是 4 个字节,uint32_t 也是 4 个字节。在这种情况下可以正常工作。你现在可以清除downvote ;)
      【解决方案4】:

      首先添加2个指针没有定义。所以如果你使用+操作符,你将面临编译error

      其次,输出为真,如果减去 2 个指针,它会显示指针之间有多少该类型的框。不是字节数。

      你说:

      int* p1 = &x;
      int* p2 = p1++;
      

      所以在p1p2 之间有4 个字节。它们都是int 类型。所以他们之间只有一盒int

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-16
        • 1970-01-01
        • 1970-01-01
        • 2015-01-26
        相关资源
        最近更新 更多