这个问题是在一次工作面试的笔试环节中提出的:
#include<alloc.h>
#define MAXROW 3
#define MAXCOL 4
main()
{
int (*p)[MAXCOL];
p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)));
}
这个进程分配了多少字节?
说实话,我没有回答这个问题。我不理解对 p
的赋值。
有人可以解释一下答案是什么以及如何推导出来吗?
这个问题是在一次工作面试的笔试环节中提出的:
#include<alloc.h>
#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
语句分配了一个类型为P的内存缓冲区大小的MAXROW倍。因此,总共分配了MAXROW*MAXCOL个整数。实际字节数将取决于目标平台。
此外,C运行时可能还使用了其他内存(作为malloc中的内部簿记以及在调用main
之前发生的各种进程初始化位等),这也完全取决于平台。
p
是指向一个由int
类型的MAXCOL
个元素组成的数组的指针,因此sizeof *p
(括号是多余的)是这样一个数组的大小,即MAXCOL*sizeof(int)
。
malloc
返回值上的强制类型转换是不必要、丑陋和被认为是有害的。在这种情况下,它隐藏了一个严重的错误:由于缺少原型,malloc
被隐式地假定返回int
,而这与其正确的返回类型void *
不兼容,从而导致未定义行为。
malloc
分配多少内存 - 这是一个下限 - malloc
完全可以根据其内部使用的任何固定大小桶或页面大小来加速其算法而进行舍入。此外,程序可能会从其他初始化代码中分配堆 - 在比较 p
和显式请求的 malloc
的期望时,请注意不要包括它们。 - Tony DelroyMAXCOL*sizeof(int)
是 *p
的大小,而不是分配的内存数量。 - David GelharMAXCOL * sizeof(int)
是正确的答案...他只是说这是sizeof *p
的计算结果。在实际调用malloc
时,这个值会乘以MAXROW。 - Tony Delroysizeof(*p)
的值为 MAXCOL*sizeof(int)
。因此总共分配了 MAXROW*MAXCOL*sizeof(int)
字节。
您可能希望查看cdecl,以获取将C声明翻译为英语的帮助。在这种情况下,int (*p)[4];
变成了 declare p as pointer to array 4 of int
。
cdecl
。 (最初我认为声明是函数指针数组,而不是原始整数) - Billy ONeal#include<alloc.h>
#define MAXROW 3
#define MAXCOL 4
main() {
int (*p)[MAXCOL];
p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p));
}
sizeof(int(*)[MAXCOL])
的空间,虽然看起来比较吓人,但实际上几乎总是与sizeof(void*)
、sizeof(int*)
或其他指针大小相同。显然,指针的大小决定了应用程序的位数分类,因此该指针的大小与之对应。malloc
获取的一些内存...malloc( MAXROW * sizeof(*p) )
sizeof(*p)
是指向p
的int
数组的大小,即sizeof(int) * MAXCOL
,因此我们得到
malloc( MAXROW * (sizeof(int) * MAXCOL) )
从堆中请求。为了举例说明,如果我们假设常见的32位int
大小,那么我们需要48个字节。实际使用可能会被舍入到堆例程感觉合适的任何大小(堆例程通常使用固定大小的“桶”来加速操作)。
要确认这种期望,请将日志函数替换为malloc()
:
#include <stdio.h>
#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),或者堆内存恰好从一个可表示为int
的地址开始(即所有被截断的位都是0),那么稍后对指针的解引用可能会起作用。便宜广告:C++除非看到原型,否则无法编译。
话虽如此,也许您的alloc.h包含了malloc的原型...我没有alloc.h,所以我猜它不是标准的。
任何程序还将为许多其他东西分配内存,例如提供一些上下文的堆栈帧,其中可以调用main()。该内存的数量因编译器、版本、编译器标志、操作系统等而异。
我非常不喜欢这样的问题,因为我认为作为一名工程师,运行实验比假设自己知道在做什么要好得多 - 尤其是如果有怀疑的理由,例如程序不能按预期工作或有人制造了诡计性问题。
#include <stdlib.h>
#include <stdio.h>
#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);
}
int main()
。 - Billy ONealint (*p)[MAXCOL]
== int (*p)[4]
== "指向整型数组4的指针"(见下面的注释)
sizeof(*p)
等于 p 指向的内容大小,即 4 * sizeof(int)
。将其乘以 MAXROW,得到最终答案:
12 * sizeof(int)
注意: 这与以下的语法形式不同:
int *p[MAXCOL]
== int *p[4]
== "指向整型的指针数组,包含4个元素"
括号的位置对于意义非常重要!
//#include<alloc.h>
#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个整数组成的数组的指针。每个整数是32位=4字节。数组中的4个整数* 4字节=16。
sizeof(*p)
为什么不是4?因为它是指向的大小,而不是p的大小。要成为p的大小,它必须是sizeof(p)
,这将是4,因为p是一个指针。
严谨地说,您可以添加:
如果机器是64位的(比如说),答案应该是96。如果没有非标准的alloc.h
,那么零字节怎么样?这甚至无法编译。如果无法编译,则无法运行,如果无法运行,则根本无法分配任何内存。
alloc.h
无法被编译器访问到其他地方。我经常使用boost
头文件,它们并不是标准的,但我的程序编译得很好。我相信这里也有很多人使用POSIX头文件,它们也不在标准库中,但同样可以正常工作。 - Billy ONealmain()
和正确的引用。正如尼格尔·塔夫内尔所说:聪明和愚蠢之间只有一线之隔,而这个面试问题已经越过了那条线。 - mu is too short
)
是不行的。 - Charles Salvia