malloc的有趣行为()

时间:2016-09-29 13:13:41

标签: c pointers malloc allocation

这是我为GCC编译器编写的代码。

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

int main()
{
    int *p;
    p = (int *)malloc(9 * sizeof(char));
    p[0] = 2147483647;
    p[1] = 2147483647;
    p[2] = 1025;
    printf("%d, %d, %d, %d\n", sizeof(char), *(p), *(p+1), *(p+2));
}

输出如下:

1, 2147483647, 2147483647, 1025

我的问题是,虽然我只为指针分配了9个字节,但它似乎使用了所有12个字节。结果是相同的(除非编译器警告),如果我转换(char *)而不是(int *)。 malloc()的分配是否完整?即它总是以指针的数据类型的倍数分配,而不管我们分配的是什么?或者具体实施?

4 个答案:

答案 0 :(得分:7)

echo TestStatic::getB();

如果整数大小为4个字节,那么您所做的是undefined behavior。因为您分配了9个字节并使用了12。

投射没有任何效果,实际上你根本不应该在C中投射 p = (int *)malloc(9 * sizeof(char)); 的结果。

您触发未定义行为的另一个地方是使用malloc的错误格式说明符,您应该在sizeof中使用%zu而不是%dprintf })。

答案 1 :(得分:3)

正如其他人所提到的,你正在编写一个malloced缓冲区的末尾。这会调用undefined behavior

什么是未定义的行为意味着任何事情都可能发生。程序可能会崩溃,可能会产生意外结果,或者(在这种情况下)它似乎正常工作。

进行看似无关的代码更改可能会使您的程序突然崩溃。

为了说明发生了什么,这是在valgrind下运行程序的输出:

[dbush] valgrind /tmp/x1
==19430== Memcheck, a memory error detector
==19430== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==19430== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==19430== Command: /tmp/x1
==19430==
==19430== Invalid write of size 4
==19430==    at 0x40050E: main (x1.c:11)
==19430==  Address 0x4c18048 is 8 bytes inside a block of size 9 alloc'd
==19430==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==19430==    by 0x4004E9: main (x1.c:8)
==19430==
==19430== Invalid read of size 4
==19430==    at 0x40051C: main (x1.c:12)
==19430==  Address 0x4c18048 is 8 bytes inside a block of size 9 alloc'd
==19430==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==19430==    by 0x4004E9: main (x1.c:8)
==19430==
1, 2147483647, 2147483647, 1025
==19430==
==19430== HEAP SUMMARY:
==19430==     in use at exit: 9 bytes in 1 blocks
==19430==   total heap usage: 1 allocs, 0 frees, 9 bytes allocated
==19430==
==19430== LEAK SUMMARY:
==19430==    definitely lost: 9 bytes in 1 blocks
==19430==    indirectly lost: 0 bytes in 0 blocks
==19430==      possibly lost: 0 bytes in 0 blocks
==19430==    still reachable: 0 bytes in 0 blocks
==19430==         suppressed: 0 bytes in 0 blocks
==19430== Rerun with --leak-check=full to see details of leaked memory
==19430==
==19430== For counts of detected and suppressed errors, rerun with: -v
==19430== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4)

您可以从此输出中看到您正在读取和写入已分配缓冲区的末尾。

答案 2 :(得分:1)

你能够写到&#34;额外&#34;字节并不意味着它们被分配给你;它只是意味着它们存在。你没有理由期望那些字节不会神奇地&#34;未来的变化,因为你没有分配它们,如果其他代码做了,可以改变它们(并且,与你的代码不同,合法地这样做)。

答案 3 :(得分:1)

在C中,指针可以转到他们想要的任何内存。在您的代码中,您只分配了9个字节。由于C语言不提供绑定检查,您只需将指针移动到任何位置即可。但是,这并不意味着您可以控制这些内存位置。它可能导致sigsegv,应用程序崩溃或AccessViolationException(如果此代码本身由其他语言(如C#或Java)使用)。此外,这些字节可以被其他可能破坏您数据的程序修改。