理解指针(C语言):将int指针转换为char并更改值

理解指针(C语言):将int指针转换为char并更改值,c,pointers,malloc,C,Pointers,Malloc,我有下面的代码,它处理C中的指针 void f(void) { int a[4]; int *b = malloc(16); int *c; int i; printf("1: a = %p, b = %p, c = %p\n", a, b, c); c = a; for (i = 0; i < 4; i++) a[i] = 100 + i; c[0] = 200; printf("2: a[0

我有下面的代码,它处理C中的指针

void
f(void)
{
    int a[4];
    int *b = malloc(16);
    int *c;
    int i;

    printf("1: a = %p, b = %p, c = %p\n", a, b, c);

    c = a;
    for (i = 0; i < 4; i++)
         a[i] = 100 + i;

    c[0] = 200;
    printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
           a[0], a[1], a[2], a[3]);

    c[1] = 300;
    *(c + 2) = 301;
    3[c] = 302;
    printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
           a[0], a[1], a[2], a[3]);

    c = c + 1;
    *c = 400;
    printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
           a[0], a[1], a[2], a[3]);

    c = (int *) ((char *) c + 1);

    *c = 500;
    printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
           a[0], a[1], a[2], a[3]);

    b = (int *) a + 1;
    c = (int *) ((char *) a + 1);
    printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}

int
main(int ac, char **av)
{
    f();
    return 0;
}

我理解为什么a[1]是128144(当我们将int指针转换为char+1并重写500时,我们将向前移动一个字节),但我不理解为什么a[2]是256[第一位将被重写,但这不会给出256]。非常感谢您的帮助!提前感谢:)

要知道的是

c = (int *) ((char *) c + 1);

使c指向a[1]和a[2]中的一些。将c移一个字节,这使它成为一个int指针。这使得*c地址成为[1]的最后3个字节和[2]的第一个字节。画出所有的位,看看会发生什么。简短回答:您修改了
c
,使其不再具有4字节整数对齐方式,并将其设置为500修改了两个数组元素。此外,未对齐的访问通常是不允许的,并且会在某些系统上导致对齐故障

长答案:在第4步,
a[1]
包含0x00000190,它是400,
a[2]
包含0x000001d,它是301

假设[0]从内存地址0开始。以下是字节在小尾端系统中的排列方式(尾端性在这里非常重要),从左到右从0到15:

ADDR: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  
DATA: C8 00 00 00 90 01 00 00 2D 01 00 00 2E 01 00 00 
在步骤5中,您通过转换将
c
char*
对齐了一个字节,因此它指向address
05
,而不是
04
。将值500(0x000001F4)分配给它,这将覆盖05-08中的字节,从而产生以下内存:

ADDR: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  
DATA: C8 00 00 00 90 F4 01 00 00 01 00 00 2E 01 00 00  
当您阅读
a[1]
时,您会得到0x0001F490,即128144。

当您阅读
a[2]
时,您会得到0x00000100,即256。

虽然这可能不是您出现问题的原因,但我强烈建议您阅读有关严格的别名规则和未对齐的内存访问的内容。我所做的正是它给出的[1]=128144(匹配)。然而,a[2]并不是256,你能试一下吗?(我可以在我这边贴一张照片,如果有帮助的话,让我知道)这大概是未定义的行为。安德鲁为我们做了繁重的工作,并向你们展示了这是如何发生的,我把它作为一种锻炼留给你们
ADDR: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  
DATA: C8 00 00 00 90 F4 01 00 00 01 00 00 2E 01 00 00