2013-04-01 67 views
2

我想了解更多关于内存分配的知识,所以我在下面写了一些测试代码,看看如果我尝试分配比我需要的内存更小的内存会发生什么。如果我使用大小错误的malloc会发生什么?

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

typedef struct { 
    char *message; 
    int number; 
} Object; 

int main(int argc, char *argv[]) { 
    Object *obj = malloc(sizeof(Object) - 8); 
    printf("The size of the struct is: %ld\n", sizeof(Object)); 
    printf("The size of what was allocated is: %ld\n", sizeof(*obj)); 

    obj->message = "Hello there! My name is Chris!"; 
    obj->number = 435543; 

    puts(obj->message); 
    printf("%d\n", obj->number); 

    free(obj); 

    return 0; 
} 

首先,是sizeof(* obj)正确的方法来看看在这种情况下实际分配了多少内存?其次,即使我没有分配足够的空间,为什么仍然可以为结构对象赋值?

我的操作系统是Ubuntu的12.10 64位,编译器是gcc 4.7.2

这里是Valgrind的输出:

==14257== Memcheck, a memory error detector 
==14257== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==14257== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info 
==14257== Command: ./ex 
==14257== 
The size of the struct is: 16 
The size of what was allocated is: 16 
==14257== Invalid write of size 4 
==14257== at 0x400640: main (ex.c:15) 
==14257== Address 0x51f1048 is 0 bytes after a block of size 8 alloc'd 
==14257== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==14257== by 0x400604: main (ex.c:10) 
==14257== 
Hello there! My name is Chris! 
==14257== Invalid read of size 4 
==14257== at 0x40065A: main (ex.c:18) 
==14257== Address 0x51f1048 is 0 bytes after a block of size 8 alloc'd 
==14257== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==14257== by 0x400604: main (ex.c:10) 
==14257== 
435543 
==14257== 
==14257== HEAP SUMMARY: 
==14257==  in use at exit: 0 bytes in 0 blocks 
==14257== total heap usage: 1 allocs, 1 frees, 8 bytes allocated 
==14257== 
==14257== All heap blocks were freed -- no leaks are possible 
==14257== 
==14257== For counts of detected and suppressed errors, rerun with: -v 
==14257== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2) 
+0

尝试使用valgrind查看所有内存分配。 – squiguy

+0

你正在进入未定义行为的领域。未定义的行为包括程序工作正常。 – user93353

回答

2

在这种特定情况下,您可能试图分配0个字节,因为在大多数32位编译器中,sizeof(Object)的值为8。 malloc(0)将返回NULL作为其分配的无效大小,并尝试写入地址NULL肯定会导致应用程序崩溃。

但让我们假设您成功分配了4个字节,并尝试在其中写入8个字节。在一个单线程应用程序中,它应该可以毫无问题地工作,因为尽管您将写入未分配的内存空间,但它不会完全写入虚拟内存中丢失的某个疯狂地址。

Howover,如果你这样做:

Object* a = (Object*)malloc(4); 
Object* b = (Object*)malloc(4); 

这可能是真的,ab在意甲被分配。这意味着,在大多数32位编译器中,写入a->number将使用相同的值覆盖b->message,反之亦然,因为两者都将尝试将信息存储到内存中的相同空间。

+1

'malloc(0)'可能会返回一个非NULL指针,并且取消引用该指针会导致未定义的行为(请参阅C99的附录J.2)。所以,它可能会或可能不会崩溃,它是未定义的。 –

+0

我不明白。我在64位系统上。 Valgrind说我分配了8个字节,因为这个结构的大小是16.但是第二段帮助我理解了很多。 – Ci3

+0

结构大小取决于编译器,而不取决于系统。 64位系统可以运行使用32位内存地址的32位应用程序。在32位应用程序'sizeof'中,任何指针类型都是4个字节。 'int'通常也是4个字节,但在一些旧编译器中可以有2个字节,在64位编译器中最多可以有8个字节,这意味着根据这些因素,结构的大小可以是6,8,12或16个字节。 – Havenard

1

这取决于编译器和操作系统。很多时候,它最终崩溃。绝对不推荐。也可能导致缓冲区溢出。

2

这是很好,你正在做这种探索。大多数标准c库包含非标准扩展,允许您在分配内存后检查内存大小。你应该在从malloc返回后调用它,看看标准库实际上分配了多少内存,如果你想了解更多关于如何实现malloc的信息。你可能会发现像malloc(1)这样简单的东西可以返回一个相当大的内存块。

正如其他一些读者指出的,如果您要在32位系统上重新编译,您可能会要求malloc在示例代码中分配零字节。它会很乐意遵守并返回NULL

+0

很酷,但为什么我仍然能够分配给结构成员并打印它们? – Ci3

+0

您的结构大概是12个字节左右。在从malloc(1)'到'malloc(sizeof(* obj))'的任何场景中,该库可能会分配比您的结构长度更多的字节。 –

+0

'malloc(0)'可能会返回NULL,或者它可能会返回一个有效的指针,指向必须释放但无法访问的零字节的内存。这两个标准都是允许的。 –

0

要回答有关sizeof:sizeof的子问题,将根据您正在使用的类型(在C中,可变长度数组有一个单独的情况)生成结果。如果你写

T* obj = malloc (any value); 

那么的sizeof(* OBJ)只是着眼于* obj中的类型,它是T,并产生类型T的对象的大小分配是否失败不要紧和obj实际上是NULL,或者你是否分配比T的大小更少或更多的字节,甚至根本没有调用malloc并且obj是未初始化的变量也没有关系。

相关问题