1
#include <stdio.h>
main()
{
    int *ptr1 = malloc ( 2 );
    int *ptr2 = malloc ( 4 );
    int *ptr3 = malloc ( 16 );

    printf("ptr1    -  %x \n", ptr1);
    printf("ptr2    -  %x \n", ptr2);
    printf("ptr3    -  %x \n", ptr3);

    *ptr1 = 0x1111;
    *ptr2 = 0x2222;
    *ptr3 = 0x3333;
#if 1
    // silent corruption...
    *(ptr1+2) = 0xabcd;
#endif
#if 1
    // corruption
    *(ptr1+3) = 0xbeee;
#endif

     {
       int a;
       scanf("%d", &a);
     }
     free(ptr1);
     free(ptr2);
     free(ptr3);
}

在上面的程序中,我将 ptr 的地址作为 ptr1、ptr2、ptr3 之间的差异 0f 10 而不是差异 4 个字节。另外我在这里检查堆栈损坏。数据段(ptr1,ptr2,ptr3)中的值如何破坏堆栈段(a)中的值。而这种无声的腐败是什么。

4

2 回答 2

5

malloc需要为您提供您请求的字节数(或 NULL,显然),但没有规则反对给您更多。它通常在(例如)16 字节 ( 0x10) 边界上有效地分配内存。

这并不是说您可以使用比您要求的更多的东西,这是未定义的行为 (UB)。

换句话说,这是不允许的:

int *ptr1 = malloc (2);
*(ptr1+3) = 0xbeee;

因为整数必须至少是一个字节/字符的大小,所以两个字节不可能给你四个整数。

因此,即使您的整数两个字节长(现在可能不是),此语句也会尝试将该数组中的第四个整数设置为一个值。这样想(对于四字节整数):

        +---------------+
ptr1 -> | You can use   | \
        | these 2 bytes.|  \
         ---------------    *ptr1
        | But not these |  /
        | two.          | /
         ---------------
        |               | \
        |               |  \*(ptr1+1)
        |               |  /
        |               | /
        | Nor any of    | \
        | these         |  \*(ptr1+2)
        |               |  /
        |               | /
        |               | \
        |               |  \*(ptr1+3)
        |               |  /
        |               | /
        +---------------+
ptr2 -> |               |

在代码中使用幻数实际上是非常不寻常的(而且是相当糟糕的做法),一个更好的解决方案是:

int *ptr1 = malloc (sizeof (*ptr1) * N);

N获取给定数据类型的元素数组。

至于为什么你会看到某些事情发生,这真的无关紧要。一旦你进入 UB 领域,所有的赌注都会被取消。任何事情都可能发生,从按预期工作的事情到在你的 CPU 内部形成一个最终吞噬地球的裸奇点。

底线,不要这样做:-)

于 2013-09-11T02:41:26.220 回答
3
int *ptr1 = malloc ( 2 );

您为 分配 2 个字节int,在现代机器中通常至少为 4 个字节。

*(ptr1+2) = 0xabcd;

指针运算仅在它们指向数组元素或数组元素时才有效,否则它是未定义的行为,就像这里一样。

于 2013-09-11T02:29:44.990 回答