内存分配问题
在面试的书面回合中提出了这个问题:
#include #define MAXROW 3 #define MAXCOL 4 main() { int (*p)[MAXCOL]; p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p))); }
进程中分配了多少字节?
说实话,我没有回答这个问题。 我不明白对p
的任务。
任何人都可以解释一下答案是什么以及如何推断出来?
它取决于平台。
int (*p)[MAXCOL];
声明一个指向MAXCOL元素宽整数数组的指针(在这种情况下MAXCOL当然是4)。 因此,该指针的一个元素是目标平台上的4*sizeof(int)
。
malloc
语句分配内存缓冲区MAXROW乘以P中包含的类型的大小。因此,总共分配MAXROW * MAXCOL整数。 实际字节数取决于目标平台。
此外,C运行时可能会使用额外的内存(作为malloc中的内部bookeeping,以及在调用main
之前发生的各种进程初始化位),这也完全取决于平台。
p
是指向int
类型的MAXCOL
元素数组的指针,因此sizeof *p
(括号是多余的)是这样一个数组的大小,即MAXCOL*sizeof(int)
。
对malloc
的返回值的malloc
是不必要的,丑陋的,并且被认为是有害的 。 在这种情况下,它隐藏了一个严重的错误:由于缺少原型,假定malloc
隐式返回int
,这与其正确的返回类型( void *
)不兼容,从而导致未定义的行为。
sizeof(*p)
将是MAXCOL*sizeof(int)
。 所以完全MAXROW*MAXCOL*sizeof(int)
的字节数进行分配。
您可能需要查看cdecl以获取将C声明翻译成英语的帮助。 在这个例子中, int (*p)[4];
变为declare p as pointer to array 4 of int
。
#include #define MAXROW 3 #define MAXCOL 4 main() { int (*p)[MAXCOL]; p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)); }
进程中分配了多少字节?
p是一个指针,因此将占用堆栈上的sizeof(int(*)[MAXCOL])
,这可能看起来令人生畏,但它几乎总是与sizeof(void*)
, sizeof(int*)
或任何其他指针相同。 显然,指针大小使应用程序的分类为16,32,64等。 位,并且此指针将相应地resize。
然后p指向从malloc
获得的一些内存…
malloc( MAXROW * sizeof(*p) )
sizeof(*p)
是p
指向的int
数组的大小,即sizeof(int) * MAXCOL
,所以我们得到
malloc( MAXROW * (sizeof(int) * MAXCOL) )
从堆请求。 为了便于说明,如果我们假设常见的32位int
大小,我们将查看48个字节。 实际使用情况可以四舍五入到堆例程的感觉(堆例程经常使用固定大小的“桶”来加速其操作)。
要确认此期望,只需将日志记录函数替换为malloc()
:
#include #define MAXROW 3 #define MAXCOL 4 void* our_malloc(size_t n) { printf("malloc(%ld)\n", n); return 0; } int main() { int (*p)[MAXCOL]; p = (int (*)[MAXCOL]) our_malloc(MAXROW*(sizeof(*p))); }
我的Linux机箱输出:
malloc(48)
malloc的返回指针转换为p的类型的事实不会影响完成的内存分配量。
正如R强烈观察到的那样,缺少malloc
原型会导致编译器期望malloc
返回int
而不是实际返回的void*
。 实际上,指针中最小的sizeof(int)字节很可能在转换后仍然存在,如果sizeof(void *)恰好等于sizeof(int),或者 – 更脆弱 – 堆内存恰好开始尽管指针的大小较大(即所有截断的位都是0),但是在int
表示的地址处,然后稍后取消引用指针可能会起作用。 廉价的插件:除非看到原型,否则C ++不会编译。
也就是说,也许你的alloc.h包含一个malloc原型……我没有alloc.h所以我猜它是非标准的。
任何程序也会为许多其他事物分配内存,例如提供一些可以调用main()的上下文的堆栈帧。 内存量因编译器,版本,编译器标志,操作系统等而异。
int (*p)[MAXCOL]
== int (*p)[4]
==“指向int的数组4的指针”(见下面的注释)
sizeof(*p)
将是p指向的,即4 * sizeof(int)
。 乘以MAXROW,您的最终答案是:
12 * sizeof(int)
注意:这与以下情况形成对比:
int *p[MAXCOL]
== int *p[4]
==“指向int的指针的数组4”
圆括号有很大的不同!
应该是MAXROW * MAXCOL * sizeof(int)字节数
我真的不喜欢这样的问题,因为我认为作为一名工作工程师来运行实验比假设你知道自己在做什么要好得多 – 特别是如果出于怀疑的原因,例如程序没有按预期工作或有人制作技巧的问题。
#include #include #define MAXROW 3 #define MAXCOL 4 main() { int (*p)[MAXCOL]; int bytes = MAXROW * (sizeof(*p)); p = (int (*)[MAXCOL]) malloc(bytes); printf("malloc called for %d bytes\n", bytes); }
在32位Linux系统上:
gcc test.c
./a.out
malloc调用了48个字节
(编辑删除乘以maxrow两次的粘贴事故,产生错误的144字节大小)
在codepad.org中运行以下代码:
//#include #define MAXROW 3 #define MAXCOL 4 int main() { int (*p)[MAXCOL]; p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p))); int x = MAXROW*(sizeof(*p)); printf("%d", x); return 0; }
打印出48。
为什么? 因为MAXROW
是3,而sizeof(*p)
是16,所以得到3 * 16。
为什么sizeof(*p)
16? 因为MAXCOL
是4,所以p是指向4个int的数组的指针。 每个int是32位= 4个字节。 数组中的4个整数* 4个字节= 16。
为什么sizeof(*p)
不是4? 因为它是p指向的大小,而不是p的大小。 要成为p的大小,它必须是sizeof(p)
,它将是4,因为p是指针。
迂腐地你可以添加:
- 如果机器是64位(比方说),答案是96。
- 正如问题所述“在进程中分配了多少字节?”,您需要为指针p添加4个字节。
- malloc可以分配比你要求的更多(但不能少)所以这个问题无法回答。
- 与2类似,您可以争辩说,由于进程也在加载系统dll(如C运行时dll)以便运行,因此它也为这些进行了分配空间。 然后,您可以争论由其他(非系统)进程注入到进程中的dll分配的空间,例如由Actual Window Manager及其类似注入的进程。 但是我们想要得到多少迂腐?
但我认为问题实际上是要求48,可能会有额外的功劳来解释96。
零字节怎么样,因为如果没有非标准的alloc.h
,它甚至都不能编译。 如果您无法编译它,则无法运行它,如果您无法运行它,它根本无法分配任何内存。