【问题标题】:Why does second printf print 0为什么第二个 printf 打印 0
【发布时间】:2013-10-29 11:53:46
【问题描述】:
#include<stdio.h>
int main()
{
    char arr[] = "somestring";
    char *ptr1 = arr;
    char *ptr2 = ptr1 + 3;
    printf("ptr2 - ptr1 = %ld\n", ptr2 - ptr1);
    printf("(int*)ptr2 - (int*) ptr1 = %ld",  (int*)ptr2 - (int*)ptr1);
    return 0;
}

我明白了

 ptr2 - ptr1

给出 3 但无法弄清楚为什么第二个 printf 打印 0。

【问题讨论】:

  • 提问是否投反对票?
  • @Jerry ,我没有。这是我参加的一些 C 测验。我弄错了。
  • 尝试调试并检查值(观看)
  • @lan 根据指针数学当你添加1 然后结果将指向相同类型的下一个位置假设arr == 12 然后ptr1 == 12 然后ptr1 + 3 == 15 等等ptr2 == 15。现在 ptr1 == 12 在添加 + 然后 (int*)ptr1 + 1 = 16sizeof (int*) == 4 的系统之前添加 int*
  • 这是未定义的行为(UB)吗?取消引用 (int*)ptr1 将是,因为它没有正确对齐(取决于平台)。但也许连减法本身也是 UB 的指针对齐不正确?

标签: c pointers output


【解决方案1】:

这是因为当你减去两个指针时,你得到的指针之间的距离是元素个数,而不是字节数。

(char*)ptr2-(char*)ptr1  // distance is 3*sizeof(char), ie 3
(int*)ptr2-(int*)ptr1  // distance is 0.75*sizeof(int), rounded to 0 

编辑:我说演员强制指针对齐是错误的

【讨论】:

  • Sizeof int* 在我的机器上是 8 字节。然而 ptr2=ptr1+5 给出 1。所以我假设即使大小为 8 字节,它也可以在 4 字节边界上对齐。我说的对吗?
  • @IanMcGrath sizeof(int) 是 4,而不是 sizeof(int*)
  • @BenoitBlanchon,现在说得通了。谢谢。
  • 对不起,我走得太快了。
【解决方案2】:

如果要检查地址之间的距离,不要使用(int *)(void *)ptrdiff_t 是一种能够表示任何有效指针减法运算结果的类型。

#include <stdio.h>
#include <stddef.h>

int main(void)
{
    char arr[] = "somestring";
    char *ptr1 = arr;
    char *ptr2 = ptr1 + 3;
    ptrdiff_t diff = ptr2 - ptr1;

    printf ("ptr2 - ptr1 = %td\n", diff);
    return 0;
}

编辑:正如@chux 所指出的,use "%td" character for ptrdiff_t

【讨论】:

  • 不知道。有一个 +1,我接受了 Benoit Blanchon 的回复,因为它解释了为什么它是 0。知道你提到的内容仍然很有用。
  • 根据 C11dr 6.5.6 9,区别在于类型 ptrdiff_t。因此,将差异转换为 (ptrdiff_t) 类型不会改变任何内容。对于printf() 这种类型,应该使用t 修饰符,如printf ("%td\n", ptr2 - ptr1)
【解决方案3】:

使用int* 投射char 指针会使其与4 字节对齐(这里考虑到int 是4 字节)。虽然 ptr1ptr2 相距 3 个字节,但将它们转换为 int* 会产生相同的地址 - 因此是结果。

【讨论】:

    【解决方案4】:

    这是因为sizeof(int) == 4

    每个字符占用 1 个字节。您的字符数组在内存中如下所示:

    [s][o][m][e][s][t][r][i][n][g][0]
    

    当你有一个 int 数组时,每个 int 占用四个字节。存储 '1' 和 '2' 在概念上看起来更像这样:

    [0][0][0][1][0][0][0][2]
    

    因此,整数必须与 4 字节边界对齐。您的编译器将地址别名为最低整数边界。您会注意到,如果您使用 4 而不是 3,这将按预期工作。

    您必须执行减法才能做到这一点的原因(只是将转换后的指针传递给 printf 不会这样做)是因为printf 不是严格类型的,即%ld 格式不包含参数是一个int指针的信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-25
      • 2014-01-17
      相关资源
      最近更新 更多