未知的C代码输出

时间:2015-07-08 06:00:02

标签: c pointers undefined-behavior unsigned-integer

以下代码如何给出答案,如2036,2036,2036。

以下C代码的输出是什么?假设x的地址是2000(十进制),整数需要四个字节的内存。

int main()
{ 
   unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, 
                           {7, 8, 9}, {10, 11, 12}};
   printf("%u, %u, %u", x+3, *(x+3), *(x+2)+3);
}

3 个答案:

答案 0 :(得分:3)

正如您刚刚发现的那样,如果您不发布经过精心设计的代码,那么人们可能会对此感到有点苛刻。要打印地址,请使用%p中的<inttypes.h>或来自PRIXPTR的宏,例如uintptr_t并投射到%p

只使用#include <stdio.h> int main(void) { unsigned int x[4][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } }; printf("%p\n", (void *)x); printf("%p, %p, %p\n", (void *)(x+3), (void *)(*(x+3)), (void *)(*(x+2)+3)); return 0; } ,您的代码应该是:

x+3

现在你已经定义了行为,虽然这些值不像2000和2036那样方便。

但是,int是数组开始后第4个sizeof(int) == 4数组的地址,所以假设x如上所述,那就是{ {1}} - 如果x是2000,则为2036。

*(x+3)是第四个数组开头的地址;在同样的假设下,这是在2036年。

*(x+2)+3将3添加3 int的第三个数组的地址,然后再添加3个。x这也是x开始后的36个字节,如果0x7fff5800a440 0x7fff5800a464, 0x7fff5800a464, 0x7fff5800a464 是2000,则结束于2036。

在我的64位计算机上,输出显示为:

((MainActivity) getActivity()).showTwoLinearLayout();
((MainActivity) getActivity()).hideCategoryContainerLayout();

Hex 0x24当然是36位小数。

答案 1 :(得分:1)

   2000  4   8  12  16  20  24  28   32  36  40  44  48
     +---+---+---+---+---+---+---+---+---+---+---+---+
     | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
     +---+---+---+---+---+---+---+---+---+---+---+---+
   x {                                                } size = 48
      {   x[0]  } {   x[1]  } {   x[2]  } {   x[3]  }   size = 12 * 4

x = 2000
x + 3 = &x[3] = 2000 + 3 * ( 3 * 4) = 2036
                       ^    ^-----^ size of int[3]
                      index
*(x+2) + 3 = &x[2] + 3 off = 2000 + 2 * (3 * 4) + 3 * 4 = 2036

xx[0]的地址相同,其类型(以及大小)不同。

您应该在return 0功能的末尾添加main。您的print语句也应如下所示:

printf("%p, %p, %p\n", (void *)(x+3), (void *)*(x+3), (void *)(*(x+2)+3));
/*      ^^  ^^  ^^^^   ^^^^^^^^^   ^  ^^^^^^^^        ^^^^^^^^^        ^ */

对于明确界定的行为。

答案 2 :(得分:1)

修改:正如Jonathan Leffler所指出的那样,我应该在打印(void*)之前投射到%p

也许这将澄清内存寻址方面的情况:

#include <stdio.h>

int main() {
    unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};

    // Output: Address, 1
    printf("%p, %u\n", (void*)(x),      **x);

    // Output: Address + 12, 4
    printf("%p, %u\n", (void*)(x+1),    **(x+1));

    // Output: Address + 24, 7
    printf("%p, %u\n", (void*)(x+2),    **(x+2));

    // Output: Address + 4, 2
    printf("%p, %u\n", (void*)((*x)+1), *(*(x)+1));

    return 0;
}
  • **x应该用来获取x[0][0]
  • **(x+1)应该用来获取x[1][0]
  • **(x+2)应该用来获取x[2][0]
  • *(*(x)+1)应该用来获取x[0][1]

为了更加清晰:

#include <stdio.h>

int main() {
    unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};

    printf("%p, %u\n", (void*)(x),      **x);       // Output: Address, 1
    printf("%u\n",                      x[0][0]);   // Output: 1

    printf("%p, %u\n", (void*)(x+1),    **(x+1));   // Output: Address + 12, 4
    printf("%u\n",                      x[1][0]);   // Output: 4

    printf("%p, %u\n", (void*)(x+2),    **(x+2));   // Output: Address + 24, 7
    printf("%u\n",                      x[2][0]);   // Output: 7

    printf("%p, %u\n", (void*)((*x)+1), *(*(x)+1)); // Output: Address + 4, 2
    printf("%u\n",                      x[0][1]);   // Output: 2

    return 0;
}