最近有人在我使用的一段代码中向我指出
char* name = malloc(256*sizeof(char));
// more code
free(name);
Run Code Online (Sandbox Code Playgroud)
我的印象是这种设置阵列的方式与使用相同
char name[256];
Run Code Online (Sandbox Code Playgroud)
并且两种方式都需要使用free().我错了,如果是这样,有人可以用低级别的术语解释有什么区别?
Ned*_*der 28
在第一个代码中,内存在堆上动态分配.需要使用free()释放内存.它的寿命是任意的:它可以跨越功能边界等.
在第二个代码中,256个字节在堆栈上分配,并在函数返回时自动回收(如果它在所有函数之外,则在程序终止时).所以你不必(也不能)调用free()就可以了.它不会泄漏,但它也不会超出功能的终点.
根据内存要求在两者之间进行选择.
附录(Pax):
如果我可以添加这个,Ned,大多数实现通常会提供比堆栈更多的堆(至少在默认情况下).这通常不会对256字节有影响,除非你已经耗尽了堆栈或做了很多递归的东西.
此外,sizeof(char)根据标准始终为1,因此您不需要多余的乘法.即使编译器可能会优化它,它也会让代码变得丑陋IMNSHO.
结束附录(Pax).
并且两种方式都需要使用free().
不,只有第一个需要免费使用.第二个是在堆栈上分配的.这使得分配速度极快.看这里:
void doit() {
/* ... */
/* SP += 10 * sizeof(int) */
int a[10];
/* ... (using a) */
} /* SP -= 10 */
Run Code Online (Sandbox Code Playgroud)
在创建它时,编译器在编译时知道它的大小,并在堆栈中为它分配正确的大小.堆栈是位于某处的大块连续内存.将东西放在堆栈中只会增加(或减少,具体取决于您的平台)stackpointer.超出范围将反过来,并释放您的数组.这将自动发生.因此创建的变量具有自动存储持续时间.
使用malloc是不同的.它会命令一些任意大的内存块(来自一个名为freestore的地方).运行时必须查找相当大的内存块.大小可以在运行时确定,因此编译器通常无法在编译时对其进行优化.因为指针可能超出范围,或者被复制,所以分配的内存与分配内存地址的指针之间没有固有的耦合,所以即使你很久以前离开了函数,内存仍然被分配.如果时间已经到了,你必须自由地调用你手动从malloc获得的地址.
C的一些"最近"形式称为C99,允许您为数组提供运行时大小.即你被允许这样做:
void doit(int n) {
int a[n]; // allocate n * sizeof(int) size on the stack */
}
Run Code Online (Sandbox Code Playgroud)
但如果您没有理由使用它,最好避免使用该功能.一个原因是它不是故障安全的:如果没有可用的内存,任何事情都可能发生.另一个原因是C99在编译器中不是很便携.
这里有第三种可能性,即数组可以在函数外部声明,但静态地,例如,
// file foo.c
char name[256];
int foo() {
// do something here.
}
Run Code Online (Sandbox Code Playgroud)
我对另一个关于SO的问题的回答感到相当惊讶,有人觉得这在C中是不合适的; 这里甚至都没有提到,我有点困惑和惊讶(比如"这些天他们在学校里教孩子的原因是什么?").
如果使用此定义,则内存将静态分配,既不在堆上也不在堆栈中,而是在映像中的数据空间中.因此,既不必像malloc/free一样进行管理,也不必担心地址被重用,就像使用自动定义一样.
在这里回忆整个"声明"与"定义"的事情是有用的.这是一个例子
/* example.c */
char buf1[256] ; /* declared extern, defined in data space */
static char buf2[256] ; /* declared static, defined in data space */
char * buf3 ; /* declared extern, defined one ptr in data space */
int example(int c) { /* c declared here, defined on stack */
char buf4[256] ; /* declared here, defined on stack */
char * buf5 = malloc(256)] /* pointer declared here, defined on stack */
/* and buf4 is address of 256 bytes alloc'd on heap */
buf3 = malloc(256); /* now buf3 contains address of 256 more bytes on heap */
return 0; /* stack unwound; buf4 and buf5 lost. */
/* NOTICE buf4 memory on heap still allocated */
/* so this leaks 256 bytes of memory */
}
Run Code Online (Sandbox Code Playgroud)
现在在一个完整的不同文件中
/* example2.c */
extern char buf1[]; /* gets the SAME chunk of memory as from example.c */
static char buf2[256]; /* DIFFERENT 256 char buffer than example.c */
extern char * buf3 ; /* Same pointer as from example.c */
void undoes() {
free(buf3); /* this will work as long as example() called first */
return ;
}
Run Code Online (Sandbox Code Playgroud)