为什么* int_one处的内存修改不会更改* int_two处的内存值?

时间:2018-08-17 22:06:30

标签: c memory malloc

我写了一段非常简单的C代码:

int main(void) {
    void *area = malloc(2 * sizeof(int));
    unsigned int *int_one = (unsigned int *) area;
    unsigned int *int_two = ((unsigned int *) area) + 3;

    *int_two = 4293422034;
    *int_one = 2;

    printf("%u\n%u\n", *int_two, *int_one);

    return 0;
}

sizeof(int)在我的计算机上是4。根据我的理解,修改地址int_one上的内存不应该影响存储在地址int_two上的值吗?

修改*int_one会更改内存的前4个字节。地址area(也许不是全部为4,但是足以保证我期望的结果吗?),地址int_two处的整数从整数int_one的最后一个字节开始。 >

因此,更改int_one处的内存不应该对int_two处的内存有影响吗? 然而,printf调用分别产生42934220342

我确保使用无符号变量来避免2s补数和负值之间的混淆,并为*int_one使用一个小的值来保证其最后一个字节的变化(不知道这是否正确? )

我没有得到什么?

2 个答案:

答案 0 :(得分:3)

运算符'+'应用于指针时,会将指针n增大为其所指向对象的大小。因此,将int*增加3不会增加3个字节,而是增加3*sizeof(int)个字节。

答案 1 :(得分:2)

指针算术按指针指向的类型的大小缩放。 (在您的情况下为sizeof(unsigned int))。如果您想将地址增加3个字节,则需要在添加3之前强制转换为(char*),但是将其转换为unsigned*指针将导致违反 undefined behavior 的行为对齐要求(6.3.2.3p7)和取消引用指针会违反严格的别名规则(6.5p7),从而使程序“更加不确定”。

要真正实现这种类型的校正,您需要使用memcpy(或union s)。

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    void *area = malloc(2 * sizeof(int));
    if(!area) return EXIT_FAILURE;
    unsigned int *int_one_p = area;
    void *int_two_p = (((char*) area) + 3); /*saving this to an (unsigned*) would be UB*/

    memcpy(int_two_p,&(unsigned){4293422034},sizeof(unsigned));
    memcpy(int_one_p,&(unsigned){2},sizeof(unsigned));

    unsigned one,two;
    memcpy(&one,int_one_p, sizeof(one));
    memcpy(&two,int_two_p, sizeof(two));

    printf("%u\n%u\n", two, one);

    return 0;
}