最近有人在我的一段代码中向我指出我正在使用
char* name = malloc(256*sizeof(char));
// more code
free(name);
我的印象是这种设置数组的方式与使用
相同char name[256];
并且两种方式都需要使用free()。我错了,如果有的话,有人可以用低级别的术语解释这有什么区别吗?
答案 0 :(得分:27)
在第一个代码中,内存是在堆上动态分配的。需要使用free()释放内存。它的生命周期是任意的:它可以跨越函数边界等。
在第二个代码中,256个字节在堆栈上分配,并在函数返回时自动回收(如果它在所有函数之外,则在程序终止时)。所以你不必(也不能)调用free()就可以了。它不会泄漏,但它也不会超出功能的终点。
根据内存要求在两者之间进行选择。
附录(Pax):
如果我可以添加Ned,大多数实现通常会提供比堆栈更多的堆(至少在默认情况下)。这通常不会对256字节有影响,除非你已经耗尽了堆栈或做了很多递归的东西。
此外,sizeof(char)根据标准始终为1,因此您不需要多余的乘法。即使编译器可能会优化它,它也会使代码变得丑陋IMNSHO。
结束附录(Pax)。
答案 1 :(得分:7)
并且两种方式都需要使用free()。
不,只有第一个需要免费使用。第二个是在堆栈上分配的。这使得分配速度极快。看这里:
void doit() {
/* ... */
/* SP += 10 * sizeof(int) */
int a[10];
/* ... (using a) */
} /* SP -= 10 */
创建它时,编译器在编译时知道它的大小,并在堆栈中为它分配正确的大小。堆栈是位于某处的大块连续内存。将东西放在堆栈中只会增加(或减少,具体取决于您的平台)stackpointer。超出范围将反过来,并释放您的数组。这将自动发生。因此,以这种方式创建的变量具有自动存储持续时间。
使用malloc是不同的。它将订购一些任意大的内存块(来自一个名为 freestore 的地方)。运行时必须查找相当大的内存块。大小可以在运行时确定,因此编译器通常无法在编译时对其进行优化。因为指针可能超出范围,或者被复制,所以分配的内存与分配内存地址的指针之间没有固有的耦合,所以即使你很久以前离开了函数,内存仍然被分配。如果时间已经到了,你必须自由地调用你手动从malloc获得的地址。
一些名为C99的“最近”形式的C允许您为数组提供运行时大小。即你被允许这样做:
void doit(int n) {
int a[n]; // allocate n * sizeof(int) size on the stack */
}
但如果您没有理由使用它,最好避免使用该功能。一个原因是它不是故障安全的:如果没有可用的内存,任何事情都可能发生。另一个原因是C99在编译器中不是很便携。
答案 2 :(得分:5)
这里有第三种可能性,即数组可以在函数外部声明,但是静态地,例如,
// file foo.c
char name[256];
int foo() {
// do something here.
}
我对另一个关于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 */
}
现在在一个完整的不同文件中
/* 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 ;
}
答案 3 :(得分:2)
这是不正确的 - 数组声明不需要免费。此外,如果这是在一个函数内,它被分配在堆栈上(如果内存服务)并且在函数返回时自动释放 - 不要将对它的引用传递给调用者!
答案 4 :(得分:2)
细分陈述
char* name = malloc(256*sizeof(char)); // one statement
char *name; // Step 1 declare pointer to character
name = malloc(256*sizeof(char)); // assign address to pointer of memory from heap
name[2]; // access 3rd item in array
*(name+2); // access 3rd item in array
name++; // move name to item 1
翻译:name现在是指向字符的指针,该字符被分配了堆上某些内存的地址
char name[256]; // declare an array on the stack
name++; // error name is a constant pointer
*(name+2); // access 3rd item in array
name[2]; // access 3rd item in array
char *p = name;
p[2]; // access 3rd item in array
*(p+2); // access 3rd item in array
p++; // move p to item 1
p[0]; // item 1 in array
翻译:Name是指向指向堆栈中某些内存的字符的常量指针
在C数组中,指针或多或少都是一样的。数组是内存的常量指针。主要区别在于,当您调用malloc时,您将从堆中获取内存,并且必须从堆中释放从堆中获取的任何内存。当您声明具有大小的数组时,它将从堆栈中分配内存。你无法释放这个内存,因为free是从堆中释放内存。当前程序单元返回时,将自动释放堆栈中的内存。在第二个例子中,free(p)也是一个错误。 p是堆栈上名称数组的指针。因此,通过释放p,您试图释放堆栈中的内存。
这与以下内容没有什么不同:
int n = 10;
int *p = &n;
在这种情况下,释放p将是一个错误,因为p指向n,它是堆栈上的变量。因此,p在堆栈中保存一个内存位置,无法释放。
int *p = (int *) malloc(sizeof(int));
*p = 10;
free(p);
在这种情况下,free是正确的,因为p指向由malloc分配的堆上的内存位置。
答案 5 :(得分:0)
取决于您运行此处的位置,堆栈空间可能会非常宝贵。例如,如果你正在为Verizon / Alltel手机编写BREW代码,那么你通常只能使用微小的堆栈,但却不断增加堆访问权。
另外,由于char []最常用于字符串,所以允许字符串构造方法为所讨论的字符串分配所需的内存并不是一件坏事,而不是希望永远都是256(或者无论你判定什么数字都足够了。