Someone here recently pointed out to me in a piece of code of mine I am using
最近有人在我的一段代码中向我指出了我正在使用的代码
char* name = malloc(256*sizeof(char));
// more code
free(name);
I was under the impression that this way of setting up an array was identical to using
我的印象是这种设置阵列的方式与使用相同
char name[256];
and that both ways would require the use of free(). Am I wrong and if so could someone please explain in low level terms what the difference is?
并且两种方式都需要使用free()。我错了,如果是这样,有人可以用低级别的术语解释有什么区别?
6 个解决方案
#1
27
In the first code, the memory is dynamically allocated on the heap. That memory needs to be freed with free(). Its lifetime is arbitrary: it can cross function boundaries, etc.
在第一个代码中,内存在堆上动态分配。需要使用free()释放内存。它的寿命是任意的:它可以跨越功能边界等。
In the second code, the 256 bytes are allocated on the stack, and are automatically reclaimed when the function returns (or at program termination if it is outside all functions). So you don't have to (and cannot) call free() on it. It can't leak, but it also won't live beyond the end of the function.
在第二个代码中,256个字节在堆栈上分配,并在函数返回时自动回收(如果它在所有函数之外,则在程序终止时)。所以你不必(也不能)调用free()就可以了。它不会泄漏,但它也不会超出功能的终点。
Choose between the two based on the requirements for the memory.
根据内存要求在两者之间进行选择。
Addendum (Pax):
附录(Pax):
If I may add to this, Ned, most implementations will typically provide more heap than stack (at least by default). This won't typically matter for 256 bytes unless you're already running out of stack or doing heavily recursive stuff.
如果我可以添加这个,Ned,大多数实现通常会提供比堆栈更多的堆(至少在默认情况下)。这通常不会对256字节有影响,除非你已经耗尽了堆栈或做了很多递归的东西。
Also, sizeof(char) is always 1 according to the standard so you don't need that superfluous multiply. Even though the compiler will probably optimize it away, it makes the code ugly IMNSHO.
此外,sizeof(char)根据标准始终为1,因此您不需要多余的乘法。尽管编译器可能会将其优化掉,但它会让代码变得丑陋IMNSHO。
End addendum (Pax).
结束附录(Pax)。
#2
7
and that both ways would require the use of free().
并且两种方式都需要使用free()。
No, only the first needs the use of a free. The second is allocated on the stack. That makes it incredibly fast to allocate. Look here:
不,只有第一个需要免费使用。第二个是在堆栈上分配的。这使得分配速度极快。看这里:
void doit() {
/* ... */
/* SP += 10 * sizeof(int) */
int a[10];
/* ... (using a) */
} /* SP -= 10 */
When you create it, the compiler at compile time knows its size and will allocate the right size at the stack for it. The stack is a large chunk of continuous memory located somewhere. Putting something at the stack will just increment (or decrement depending on your platform) the stackpointer. Going out of scope will do the reverse, and your array is freed. That will happen automatically. Therefor variables created that way have automatic storage duration.
在创建它时,编译器在编译时知道它的大小,并在堆栈中为它分配正确的大小。堆栈是位于某处的大块连续内存。将东西放在堆栈中只会增加(或递减,具体取决于您的平台)stackpointer。超出范围将反过来,并释放您的数组。这将自动发生。因此创建的变量具有自动存储持续时间。
Using malloc is different. It will order some arbitrary large memory chunk (from a place called freestore). The runtime will have to lookup a reasonably large block of memory. The size can be determined at runtime, so the compiler generally cannot optimize it at compile time. Because the pointer can go out of scope, or be copied around, there is no inherent coupling between the memory allocated, and the pointer to which the memory address is assigned, so the memory is still allocated even if you have left the function long ago. You have to call free passing it the address you got from malloc manually if the time has come to do so.
使用malloc是不同的。它会命令一些任意大的内存块(来自一个名为freestore的地方)。运行时必须查找相当大的内存块。大小可以在运行时确定,因此编译器通常无法在编译时对其进行优化。因为指针可能超出范围,或者被复制,所以在分配的内存和分配内存地址的指针之间没有固有的耦合,所以即使你很久以前离开了函数,内存仍然被分配。如果时间已经到了,你必须*地调用你手动从malloc获得的地址。
Some "recent" form of C, called C99, allows you to give arrays an runtime size. I.e you are allowed to do:
C的一些“最近”形式称为C99,允许您为数组提供运行时大小。你被允许这样做:
void doit(int n) {
int a[n]; // allocate n * sizeof(int) size on the stack */
}
But that feature should better be avoided if you don't have a reason to use it. One reason is that it's not failsafe: If no memory is available anymore, anything can happen. Another is that C99 is not very portable among compilers.
但如果您没有理由使用它,最好避免使用该功能。一个原因是它不是故障安全的:如果没有可用的内存,任何事情都可能发生。另一个原因是C99在编译器中不是很便携。
#3
5
There is a third possibility here, which is that the array can be declared external to a function, but statically, eg,
这里有第三种可能性,即数组可以在函数外部声明,但静态地,例如,
// file foo.c
char name[256];
int foo() {
// do something here.
}
I was rather surprised in answers to another question on SO that someone felt this was inappropriate in C; here's it's not even mentioned, and I'm a little confused and surprised (like "what are they teaching kids in school these days?") about this.
我对另一个关于SO的问题的答案感到相当惊讶,有人认为这在C中是不合适的;这里甚至都没有提到,我有点困惑和惊讶(比如“这些天他们在学校教孩子们是什么?”)。
If you use this definition, the memory is allocated statically, neither on the heap nor the stack, but in data space in the image. Thus is neither must be managed as with malloc/free, nor do you have to worry about the address being reused as you would with an auto definition.
如果使用此定义,则内存将静态分配,既不在堆上也不在堆栈中,而是在映像中的数据空间中。因此既不必像malloc / free一样进行管理,也不必担心地址被重用,就像使用自动定义一样。
It's useful to recall the whole "declared" vs "defined" thing here. Here's an example
在这里回忆整个“声明”与“定义”的事情是有用的。这是一个例子
/* 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 */
}
Now in a whole different file
现在在一个完整的不同文件中
/* 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 ;
}
#4
2
This is incorrect - the array declaration does not require a free. Further, if this is within a function, it is allocated on the stack (if memory serves) and is automatically released with the function returns - don't pass a reference to it back the caller!
这是不正确的 - 数组声明不需要免费。此外,如果这是在一个函数内,它被分配在堆栈上(如果内存服务)并随函数返回自动释放 - 不要将一个引用传递回调用者!
#5
2
Break down your statement
打破你的陈述
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
Translation: name is now a pointer to character which is assigned the address of some memory on the heap
翻译: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
Translation: Name is a constant pointer to a character that points to some memory on the stack
转换:Name是指向指向堆栈上某些内存的字符的常量指针
In C arrays and pointers are the same thing more or less. Arrays are constant pointers to memory. The main difference is that when you call malloc you take your memory from the heap and any memory taken from the heap must be freed from the heap. When you declare the array with a size it is assigned memory from the stack. You can't free this memory because free is made to free memory from the heap. The memory on the stack will automatically be freed when the current program unit returns. In the second example free(p) would be an error also. p is a pointer the name array on the stack. So by freeing p you are attempting to free the memory on the stack.
在C数组中,指针或多或少是相同的。数组是内存的常量指针。主要区别在于,当您调用malloc时,您需要从堆中获取内存,并且必须从堆中释放从堆中获取的任何内存。当您使用大小声明数组时,会从堆栈中分配内存。你无法释放这个内存,因为free是从堆中释放内存。当前程序单元返回时,将自动释放堆栈中的内存。在第二个例子中,free(p)也是一个错误。 p是堆栈上名称数组的指针。因此,通过释放p,您试图释放堆栈中的内存。
This is no different from:
这与以下内容没有区别:
int n = 10;
int *p = &n;
freeing p in this case would be an error because p points to n which is a variable on the stack. Therefore p holds a memory location in the stack and cannot be freed.
在这种情况下释放p将是一个错误,因为p指向n,它是堆栈上的变量。因此,p在堆栈中保存一个内存位置,无法释放。
int *p = (int *) malloc(sizeof(int));
*p = 10;
free(p);
in this case the free is correct because p points to a memory location on the heap which was allocated by malloc.
在这种情况下,free是正确的,因为p指向由malloc分配的堆上的内存位置。
#6
0
depending on where you are running this, stack space might be at a HUGE premium. If, for example, you're writing BREW code for Verizon/Alltel handsets, you are generally restricted to miniscule stacks but have ever increasing heap access.
根据您运行此处的位置,堆栈空间可能会有巨大的溢价。例如,如果您正在为Verizon / Alltel手机编写BREW代码,那么您通常只能使用极小的堆栈,但却不断增加堆访问权限。
Also, as char[] are most often used for strings, it's not a bad idea to allow the string constructing method to allocate the memory it needs for the string in question, rather than hope that for ever and always 256 (or whatever number you decree) will suffice.
另外,由于char []最常用于字符串,所以允许字符串构造方法为所讨论的字符串分配所需的内存并不是一个坏主意,而不是希望永远和总是256(或任何数字你法令)就足够了。
#1
27
In the first code, the memory is dynamically allocated on the heap. That memory needs to be freed with free(). Its lifetime is arbitrary: it can cross function boundaries, etc.
在第一个代码中,内存在堆上动态分配。需要使用free()释放内存。它的寿命是任意的:它可以跨越功能边界等。
In the second code, the 256 bytes are allocated on the stack, and are automatically reclaimed when the function returns (or at program termination if it is outside all functions). So you don't have to (and cannot) call free() on it. It can't leak, but it also won't live beyond the end of the function.
在第二个代码中,256个字节在堆栈上分配,并在函数返回时自动回收(如果它在所有函数之外,则在程序终止时)。所以你不必(也不能)调用free()就可以了。它不会泄漏,但它也不会超出功能的终点。
Choose between the two based on the requirements for the memory.
根据内存要求在两者之间进行选择。
Addendum (Pax):
附录(Pax):
If I may add to this, Ned, most implementations will typically provide more heap than stack (at least by default). This won't typically matter for 256 bytes unless you're already running out of stack or doing heavily recursive stuff.
如果我可以添加这个,Ned,大多数实现通常会提供比堆栈更多的堆(至少在默认情况下)。这通常不会对256字节有影响,除非你已经耗尽了堆栈或做了很多递归的东西。
Also, sizeof(char) is always 1 according to the standard so you don't need that superfluous multiply. Even though the compiler will probably optimize it away, it makes the code ugly IMNSHO.
此外,sizeof(char)根据标准始终为1,因此您不需要多余的乘法。尽管编译器可能会将其优化掉,但它会让代码变得丑陋IMNSHO。
End addendum (Pax).
结束附录(Pax)。
#2
7
and that both ways would require the use of free().
并且两种方式都需要使用free()。
No, only the first needs the use of a free. The second is allocated on the stack. That makes it incredibly fast to allocate. Look here:
不,只有第一个需要免费使用。第二个是在堆栈上分配的。这使得分配速度极快。看这里:
void doit() {
/* ... */
/* SP += 10 * sizeof(int) */
int a[10];
/* ... (using a) */
} /* SP -= 10 */
When you create it, the compiler at compile time knows its size and will allocate the right size at the stack for it. The stack is a large chunk of continuous memory located somewhere. Putting something at the stack will just increment (or decrement depending on your platform) the stackpointer. Going out of scope will do the reverse, and your array is freed. That will happen automatically. Therefor variables created that way have automatic storage duration.
在创建它时,编译器在编译时知道它的大小,并在堆栈中为它分配正确的大小。堆栈是位于某处的大块连续内存。将东西放在堆栈中只会增加(或递减,具体取决于您的平台)stackpointer。超出范围将反过来,并释放您的数组。这将自动发生。因此创建的变量具有自动存储持续时间。
Using malloc is different. It will order some arbitrary large memory chunk (from a place called freestore). The runtime will have to lookup a reasonably large block of memory. The size can be determined at runtime, so the compiler generally cannot optimize it at compile time. Because the pointer can go out of scope, or be copied around, there is no inherent coupling between the memory allocated, and the pointer to which the memory address is assigned, so the memory is still allocated even if you have left the function long ago. You have to call free passing it the address you got from malloc manually if the time has come to do so.
使用malloc是不同的。它会命令一些任意大的内存块(来自一个名为freestore的地方)。运行时必须查找相当大的内存块。大小可以在运行时确定,因此编译器通常无法在编译时对其进行优化。因为指针可能超出范围,或者被复制,所以在分配的内存和分配内存地址的指针之间没有固有的耦合,所以即使你很久以前离开了函数,内存仍然被分配。如果时间已经到了,你必须*地调用你手动从malloc获得的地址。
Some "recent" form of C, called C99, allows you to give arrays an runtime size. I.e you are allowed to do:
C的一些“最近”形式称为C99,允许您为数组提供运行时大小。你被允许这样做:
void doit(int n) {
int a[n]; // allocate n * sizeof(int) size on the stack */
}
But that feature should better be avoided if you don't have a reason to use it. One reason is that it's not failsafe: If no memory is available anymore, anything can happen. Another is that C99 is not very portable among compilers.
但如果您没有理由使用它,最好避免使用该功能。一个原因是它不是故障安全的:如果没有可用的内存,任何事情都可能发生。另一个原因是C99在编译器中不是很便携。
#3
5
There is a third possibility here, which is that the array can be declared external to a function, but statically, eg,
这里有第三种可能性,即数组可以在函数外部声明,但静态地,例如,
// file foo.c
char name[256];
int foo() {
// do something here.
}
I was rather surprised in answers to another question on SO that someone felt this was inappropriate in C; here's it's not even mentioned, and I'm a little confused and surprised (like "what are they teaching kids in school these days?") about this.
我对另一个关于SO的问题的答案感到相当惊讶,有人认为这在C中是不合适的;这里甚至都没有提到,我有点困惑和惊讶(比如“这些天他们在学校教孩子们是什么?”)。
If you use this definition, the memory is allocated statically, neither on the heap nor the stack, but in data space in the image. Thus is neither must be managed as with malloc/free, nor do you have to worry about the address being reused as you would with an auto definition.
如果使用此定义,则内存将静态分配,既不在堆上也不在堆栈中,而是在映像中的数据空间中。因此既不必像malloc / free一样进行管理,也不必担心地址被重用,就像使用自动定义一样。
It's useful to recall the whole "declared" vs "defined" thing here. Here's an example
在这里回忆整个“声明”与“定义”的事情是有用的。这是一个例子
/* 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 */
}
Now in a whole different file
现在在一个完整的不同文件中
/* 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 ;
}
#4
2
This is incorrect - the array declaration does not require a free. Further, if this is within a function, it is allocated on the stack (if memory serves) and is automatically released with the function returns - don't pass a reference to it back the caller!
这是不正确的 - 数组声明不需要免费。此外,如果这是在一个函数内,它被分配在堆栈上(如果内存服务)并随函数返回自动释放 - 不要将一个引用传递回调用者!
#5
2
Break down your statement
打破你的陈述
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
Translation: name is now a pointer to character which is assigned the address of some memory on the heap
翻译: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
Translation: Name is a constant pointer to a character that points to some memory on the stack
转换:Name是指向指向堆栈上某些内存的字符的常量指针
In C arrays and pointers are the same thing more or less. Arrays are constant pointers to memory. The main difference is that when you call malloc you take your memory from the heap and any memory taken from the heap must be freed from the heap. When you declare the array with a size it is assigned memory from the stack. You can't free this memory because free is made to free memory from the heap. The memory on the stack will automatically be freed when the current program unit returns. In the second example free(p) would be an error also. p is a pointer the name array on the stack. So by freeing p you are attempting to free the memory on the stack.
在C数组中,指针或多或少是相同的。数组是内存的常量指针。主要区别在于,当您调用malloc时,您需要从堆中获取内存,并且必须从堆中释放从堆中获取的任何内存。当您使用大小声明数组时,会从堆栈中分配内存。你无法释放这个内存,因为free是从堆中释放内存。当前程序单元返回时,将自动释放堆栈中的内存。在第二个例子中,free(p)也是一个错误。 p是堆栈上名称数组的指针。因此,通过释放p,您试图释放堆栈中的内存。
This is no different from:
这与以下内容没有区别:
int n = 10;
int *p = &n;
freeing p in this case would be an error because p points to n which is a variable on the stack. Therefore p holds a memory location in the stack and cannot be freed.
在这种情况下释放p将是一个错误,因为p指向n,它是堆栈上的变量。因此,p在堆栈中保存一个内存位置,无法释放。
int *p = (int *) malloc(sizeof(int));
*p = 10;
free(p);
in this case the free is correct because p points to a memory location on the heap which was allocated by malloc.
在这种情况下,free是正确的,因为p指向由malloc分配的堆上的内存位置。
#6
0
depending on where you are running this, stack space might be at a HUGE premium. If, for example, you're writing BREW code for Verizon/Alltel handsets, you are generally restricted to miniscule stacks but have ever increasing heap access.
根据您运行此处的位置,堆栈空间可能会有巨大的溢价。例如,如果您正在为Verizon / Alltel手机编写BREW代码,那么您通常只能使用极小的堆栈,但却不断增加堆访问权限。
Also, as char[] are most often used for strings, it's not a bad idea to allow the string constructing method to allocate the memory it needs for the string in question, rather than hope that for ever and always 256 (or whatever number you decree) will suffice.
另外,由于char []最常用于字符串,所以允许字符串构造方法为所讨论的字符串分配所需的内存并不是一个坏主意,而不是希望永远和总是256(或任何数字你法令)就足够了。