Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 两个指针变量之间的差异_C_Pointers_Pointer Arithmetic - Fatal编程技术网

C 两个指针变量之间的差异

C 两个指针变量之间的差异,c,pointers,pointer-arithmetic,C,Pointers,Pointer Arithmetic,我在笔试中问过这个问题。 在我的lapi上运行下面的代码时,我得到10作为输出 #include<stdio.h> int main() { int *i, *j;/* two pointer variable*/ i = (int *)60; j = (int *)20; printf("%d \n",i-j); return 0; } 有谁能告诉我为什么输出是10您看到的是未定义的行为 指针应该指向一些有效的内存位置,而60和20则不是 引用一下标准 两个指

我在笔试中问过这个问题。 在我的lapi上运行下面的代码时,我得到10作为输出

#include<stdio.h>
int main()
{
  int *i, *j;/* two pointer variable*/
  i = (int *)60;
  j = (int *)20;
  printf("%d \n",i-j);
  return 0;
}

有谁能告诉我为什么输出是
10

您看到的是未定义的行为

指针应该指向一些有效的内存位置,而60和20则不是

引用一下标准


两个指针都应指向同一数组对象的元素,或者指向数组对象最后一个元素之后的元素,因为这不是您在代码中看到的,这是UB。

您正在计算两个指向
int
的指针之间的差异或“距离”
sizeof(int)
在您的平台上是4。60和20之间的差值为40,即10英寸之间的距离。您的实现似乎只是在评估这种差异

但是,C标准对计算两个指针之间的差异设置了限制:两个指针都必须指向数组中的元素,或者一个指针超过数组的末尾。如果您可以确保
i
j
都满足此要求,则差异评估是有效的。因为您的代码不一定满足那个条件,所以它可能有未定义的行为,在这种情况下,输出/结果可能是任何东西


另请注意,根据C标准(6.5.6加法运算符),取消引用
i
j
是未定义的行为,除非它们指向包含
int
值的有效地址。

9减去两个指针时,两个指针都应指向 相同的数组对象,或超过数组最后一个元素的一个 对象结果是两者下标的差异 数组元素

因此,程序具有未定义的行为,因为指针不指向同一数组的元素

尽管如此,编译器似乎只是生成一个用于减去两个指针的目标代码,而不管指针是否指向同一数组的元素(它信任您)

在这种情况下,根据指针算法,两个指针之间的差异是可以放置在两个指针之间的内存中的元素数

在您的情况下,
sizeof(int)
等于
4
。因此,如果
sizeof(int)
等于
4,那么大小为40字节的内存可以容纳int类型的
10
元素


这个值是10,由printf函数输出。

只有当两个指针指向同一个(数组)对象(或后面的一个)时,C标准才定义取两个指针的差,因此OP的代码调用未定义的行为。结果可能是任何事情

根据C11标准:

6.5.6/9加法运算符

减去两个指针时,两个指针都应指向同一数组对象的元素, 或超过数组对象最后一个元素一次;结果是两个参数的差异 两个数组元素的下标。结果的大小由实现定义, 其类型(有符号整数类型)是
标题中定义的
ptrdiff\u t
。 如果结果不能在该类型的对象中表示,则行为是未定义的

以下代码有效:

#include <stdio.h>

int main()
{
  int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

  int * i = a + 0;
  int * j = a + 10; /* Points "one past the last element" of the array. */

  printf("%td \n", i - j);

  return 0;
}
#包括
int main()
{
INTA[]={0,1,2,3,4,5,6,7,8,9};
int*i=a+0;
int*j=a+10;/*表示数组的“最后一个元素的一个过去”*/
printf(“%td\n”,i-j);
返回0;
}

它还打印
10

将不指向同一对象的指针之间的差异视为未定义的行为

指针根本不指向任何对象

减去代码中的指针是未定义的行为。

任何结果(10,40,65535,-1)都是错误的。

虽然这是严格未定义的行为,任何事情都是允许发生的,但是编译器在处理此类代码时很少武断,在这种情况下,结果可以解释为:

    (i - j) == ((60 - 20) / sizeof(int))

但请注意,在某些情况下,它可能不适用;例如,它可能取决于目标内存体系结构或对象的相对对齐。

听起来是正确的,但事实是否如此?考虑到代码是“错误的”?我认为10可能是一个垃圾数字。@Lewsterin为什么它错了?我想知道OP是否总是得到10作为输出。并将其与“正确”的地址进行比较。@Lewsterin,您如何知道这些地址在某些平台上是不正确的?@Lewsterin我已对答案进行了限定,具体说明了
I
j
必须满足的条件,才能使代码成为定义良好的行为。您是对的,它是UB,除非所讨论的地址恰好是数组元素的地址(或超过末尾的地址)@juanchopanza the min我看到了这段代码我知道这是UB,但只是需要其他人来提取标准引用。关键是,你不能确定
60和
20实际上可以指向同一数组中的元素。如果不是重复的话(或者最好将链接的问题标记为当前问题的重复?):@Clifford,可能是“lappy”,意思是“膝上型电脑”@CoolGuy:我知道;这个问题是修辞性的,旨在鼓励改进。也就是说,执行平台的形状因素几乎不相关。那么i+j呢?因为我的电脑上的输出是60。没有为指针类型定义+运算符,所以这样的表达式甚至无法编译。添加指针没有任何语义意义。两个对象地址之间的差异表示两个指针之间的对象数,这很有用。另一方面,两个地址的总和是没有意义的。@Avinash:你是如何让
i+j
编译的,更不用说结果是60<代码>(int)i+(int)j==80
    (i - j) == ((60 - 20) / sizeof(int))