【问题标题】:Pointer operation yields unexpected result指针操作产生意外结果
【发布时间】:2019-12-12 06:00:17
【问题描述】:

我期待下面的代码打印 4(因为浮点数是 4 个字节),但它打印 1。有人能解释一下为什么会这样吗?

#include <stdio.h>
int main()
{
    float a[4]={0.0,0.1,0.2,0.3};
    printf("%d", &a[1]-&a[0]);
    return 0;
}

【问题讨论】:

  • 总是在编译时启用编译器警告,你会看到"warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=] printf("%d", &amp;a[1]-&amp;a[0]);"
  • 指针算术由指针type控制。您的类型是 float,它是 4 字节。 &amp;a[1]-&amp;a[0] 之间有多少个 4 字节的值? printf("%ld\n", (&amp;a[1]-&amp;a[0]) * sizeof(float)); 产生了什么?

标签: c pointers subtraction


【解决方案1】:

首先,改变

  printf("%d", &a[1]-&a[0]);

到

 printf("%td", &a[1]-&a[0]);

作为两个减法的结果类型产生一个类型ptrdiff_t,%td 是该类型的转换说明符。

也就是说,引用 C11,第 §6.5.6 章,减法运算符(强调我的)

当两个指针相减时,都指向同一个数组对象的元素, 或者数组对象的最后一个元素; 结果是 两个数组元素的下标。 [....] 在 换句话说,如果表达式 P 和 Q 分别指向 i-th 和 j-th 的元素 一个数组对象,表达式(P)-(Q) 具有值i−j,前提是该值适合ptrdiff_t 类型的对象。 [....]

在您的情况下,P 是 &amp;a[1] 和 Q 是 &amp;a[0],所以 i 是 1 和 j 是 0。因此减法运算的结果是i-j,即1-0,1。

【讨论】:

  • 非常感谢您的详细解释!
【解决方案2】:

你是正确的,这两个指针相隔 4 个字节。如果你减去两个整数,你会得到 4。但是 &amp;a[1] 和 &amp;a[0] 的类型是 float *。 Pointer arithmetic in C 考虑了所指向事物的大小,因此&amp;a[1]-&amp;a[0] 为 1。

这是数组索引工作的基本方法。您可以利用这一点来遍历数组,而无需单独的索引,而是终止于诸如 NaN 之类的边界。

#include <stdio.h>
#include <math.h>

int main()
{
    float a[] = { 0.0,0.1,0.2,0.3,NAN };

    float *iter = a;
    while(!isnan(*iter)) {
        printf("%f\n", *iter);
        iter++;
    }
}

如果您改为将值转换为 unsigned int,您确实会得到 4。

printf("%u\n", (unsigned int)&a[1]-(unsigned int)&a[0]);

【讨论】:

  • 为什么是无符号整数?为什么不使用 uintptr_t?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 2012-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-28
相关资源
最近更新 更多