【问题标题】:Why the following code prints 1 as output?为什么下面的代码打印 1 作为输出?
【发布时间】:2015-04-08 16:53:02
【问题描述】:

指针的差异给出 1 作为输出..

#include<string.h>
#include<stdio.h>
int main()
{  
    int a=5,b=10;
    int *p=&a,*q=&b;
    int c=p-q;
    printf("%d",c); 
    return 0;
}

【问题讨论】:

  • 因为它们碰巧在内存中相隔一个int,并且指针算术根据底层类型而不是字节来计算。
  • 但是指针在内存中是否总是相隔一个整数..?
  • 不,这是未指定的,你不能相信这个事实,但通常你会发现它是正确的,因为编译器按照他在代码中找到局部变量的顺序在堆栈上分配局部变量。但是,如果您有 int 和 float 变量,情况就大不相同了。
  • @RajeshSethi:请注意,ab 在内存中恰好隔开一个 int(这不能保证——请参阅 DrKoch 的评论),而不是 p 和 @ 987654327@。 p-q 只是减去恰好存储在pq 中的两个指针(地址)。在机器代码级别,减去两个指针会产生字节差异(可能在实际机器上),但 C 的语义将其转换为 ints 的计数(或任何指向的类型),通过如果愿意,可以隐式除以 sizeof(int)

标签: c pointers


【解决方案1】:

减去两个不指向同一个数组的指针是没有意义的。

C11:6.5.6 加法运算符 (p8)

[...] 如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不会产生溢出;否则,行为未定义

【讨论】:

  • 可能值得一提的是,非数组对象被认为是长度为 1 的数组,这就是这句话的目的。
【解决方案2】:

你在这里减去指针:

int c=p-q;

你应该这样做:

int c=*p-*q;

这两个指针的位置接近是偶然的,否则你可以获得任何值。感谢haccks answer - 请阅读:

C11:6.5.6 加法运算符 (p8)

[...] 如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为未定义

【讨论】:

  • 似乎我错过了:“结果指向同一个数组的元素” - 减法的结果如何指向某个元素?
  • @Giorgi - 如果您在同一个数组中减去 2 个指针,那么您可能会到达同一个数组中的一个元素。例如。 arr[10] - 8 - 2 = 6 - 注意 6 是这里的有效索引。
  • @Giorgi;阅读标准中引用的完整段落,您将了解整个故事。
  • @hacks: 是的,只是附近没有那个文档
【解决方案3】:

为了让p-q 有意义,p 和 q 应该指向同一个数组。
但是你的代码中的 p-q 是未定义的

【讨论】:

    【解决方案4】:

    C通常的实现方式是一个函数在上分配一些空间,所有需要有内存地址的局部变量都放在这个空间中。

    变量以某种自然顺序放置在此内存中似乎很自然,例如它们被声明的顺序或其相反的顺序,或者可能是字母顺序。

    此外,int 变量通常会很好地装入内存。

    因此,很自然地期望ab 存储在相邻的内存位置,而&amp;a - &amp;b 将是1-1

    现在,你不应该依赖这里发生的任何合理的事情; C标准不保证你应该得到什么结果,甚至暗示首先要求差异是有意义的。这是未定义的行为,因为ab 是完全独立的对象。 C 标准允许这种差异返回1-142,甚至允许您的程序擦除您的硬盘驱动器、毁坏您的信用评分,甚至返回人类大脑无法理解的结果。类比我们称之为数字。

    【讨论】:

      【解决方案5】:

      这里,c 保存两个整数类型地址的差异。而这个差是1。5存储在一个地址中,10也存储在一个地址中。 pq 是存储这个 5 和 10 的地址。

      【讨论】:

        猜你喜欢
        • 2017-03-02
        • 2020-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多