我正在尝试更多地了解内存分配,因此我在下面编写了一些测试代码,看看如果我尝试分配比我需要的内存更小的内存会发生什么。
#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)
答案 0 :(得分:2)
你正在进行这种探索是件好事。大多数标准c库包括非标准扩展,允许您在分配后检查内存大小。从malloc返回后应该调用它,如果想要了解有关如何实现malloc
的更多信息,请查看标准库实际分配的内存量。你可能会发现像malloc(1)
这样简单的东西可以返回一个相当大的内存块。
正如其他一些读者指出的那样,如果要在32位系统上重新编译,可能会要求malloc
在示例代码中分配零字节。它会愉快地遵守并返回NULL
。
答案 1 :(得分:2)
在这种特定情况下,您可能尝试分配0个字节,因为在大多数32位编译器中sizeof(Object)
为8。 malloc(0)
将返回NULL
作为要分配的无效大小,并且尝试写入地址NULL
肯定会使您的应用程序崩溃。
但是假设您成功分配了4个字节,并尝试在其中写入8个字节。在单线程应用程序中它应该没有问题,因为尽管你将写入未分配的内存空间,但它不会写入虚拟内存中丢失的一些疯狂地址。
然而,如果你这样做:
Object* a = (Object*)malloc(4);
Object* b = (Object*)malloc(4);
a
和b
可能在系列中分配。这意味着,在大多数32位编译器中,写入a->number
将使用相同的值覆盖b->message
,反之亦然,因为两者都将尝试将信息存储到内存中的同一空间。
答案 2 :(得分:1)
它取决于编译器和操作系统。在许多人身上,它最终会崩溃。绝对不推荐。也可能导致缓冲区溢出。
答案 3 :(得分:0)
要回答关于sizeof:sizeof的子问题,会根据您使用的类型生成结果(在C中,可变长度数组有一个单独的情况)。如果你写
T* obj = malloc (any value);
然后sizeof(* obj)只查看* obj的类型,它是T,并产生类型为T的对象的大小。分配失败并且obj实际上是NULL是无关紧要,或者是否你分配的字节数少于T的大小,如果你根本没有调用malloc并且obj是一个未初始化的变量,那么它甚至不重要。