2

我正在尝试了解有关内存分配的更多信息,因此我在下面编写了一些测试代码,以查看如果我尝试分配比我需要的更小的内存会发生什么。

#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 64bit,编译器是 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)
4

4 回答 4

3

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

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

但是,如果您这样做:

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

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

于 2013-04-01T05:32:25.017 回答
2

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

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

于 2013-04-01T05:24:59.723 回答
1

这取决于编译器和操作系统。在许多情况下,它最终会崩溃。绝对不推荐。也可能导致缓冲区溢出。

于 2013-04-01T05:22:35.380 回答
1

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

T* obj = malloc (any value);

然后 sizeof (*obj) 只查看 *obj 的类型,即 T,并产生 T 类型的对象的大小。分配是否失败并且 obj 实际上为 NULL,或者您分配的是否更少并不重要或者比 T 的大小更多的字节,如果你根本没有调用 malloc 并且 obj 是一个未初始化的变量,这甚至都没有关系。

于 2014-08-03T17:59:18.160 回答