#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) 中的值。这种无声的腐败是什么。
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内部形成的裸奇点,最终吞噬地球。
底线,不要这样做:-)
int *ptr1 = malloc ( 2 );
你为一个int
分配了2个字节,这在现代机器中通常至少是4个字节。
*(ptr1+2) = 0xabcd;
指针算法仅在指向数组的元素或经过数组的元素时才有效,否则它是未定义的行为,就像这里一样。