我不需要 malloc() 这个数组吗?
Don't I have to malloc() this array?
我正在努力学习 malloc() / free() 的 C 语言规则。考虑下面的代码,它运行得很好。 (在 Linux 上,使用 GCC 编译。)具体来说,我想知道 arr
数组。我知道你必须为数组 中 中的所有结构元素分配 malloc... 但为什么你不必为数组分配 malloc 本身?
#include<stdio.h>
#include<stdlib.h>
#define ARR_SIZE 100
typedef struct containerStruct{
int data1;
int data2;
int data3;
// ...etc...
} container;
int main(){
container* arr[ARR_SIZE]; // Don't I have to malloc this?
int i;
for(i=0; i<ARR_SIZE; i++){
arr[i] = (container*) malloc (sizeof(container)); // I get why I have to malloc() here
}
...do stuff...
for(i=0; i<ARR_SIZE; i++){
free(arr[i]); // I get why I have to free() here
}
// Don't I have to free(arr) ?
return 0;
}
我猜 container* arr[ARR_SIZE];
行告诉编译器它需要知道的所有信息,以便在内存中为数组划分出 space,这就是这段代码有效的原因。
但不知何故,它仍然 "feel" 不对。当我 malloc() 某些东西时,我在堆上保留内存 space ,对吧?但是我的 container* arr[ARR_SIZE];
调用在堆栈上创建了数组。所以......容器*搬运工数组存在于堆栈中,所有这些容器*指针都指向堆上的容器结构。对吗?
container* arr[ARR_SIZE];
告诉 编译器 分配 ARR_SIZE
类型 container*
元素的数组] 并且编译器相应地分配内存。
换句话说,这类似于说 int x[5] = 0;
,其中编译器为 5 int
的数组分配了足够的 space。在您的情况下,编译器为 ARR_SIZE
个指针分配了足够的 space,container*
就是这样。现在,由您决定让这些指针 指向 有效的内存位置。为此,您可以
- 使用内存分配器函数(如您所述,它从 堆 分配内存)
- 分配相同类型的其他变量的地址(无论如何不需要从堆中分配)。
所以,最重要的是,您不需要为 数组分配任何内存。对于每个单独的数组元素,您需要使用内存分配器函数分配内存,因为您希望每个元素指向 valid 内存。
在您的 arr
声明下方,您有以下内容:
int i;
其中保留了足够 space (可能在 "stack" 上) 来存储一个 int
。这 "feel" 你也觉得不对吗?
arr
的声明没有什么不同。编译器为 container *
的 ARR_SIZE
元素数组分配足够的 space (可能在 "stack")。
您可以选择以下选项之一:
int i;
container** arr = malloc(sizeof(container*)*ARR_SIZE);
for (i=0; i<ARR_SIZE; i++)
arr[i] = malloc(sizeof(container));
// do stuff...
for(i=0; i<ARR_SIZE; i++)
free(arr[i]);
free(arr);
int i;
container* arr[ARR_SIZE];
for (i=0; i<ARR_SIZE; i++)
arr[i] = malloc(sizeof(container));
// do stuff...
for(i=0; i<ARR_SIZE; i++)
free(arr[i]);
container arr[ARR_SIZE];
// do stuff...
由于ARR_SIZE
是常数,你不妨选择最后一个选项。
由于 ARR_SIZE
是动态数组 *arr[ARR_SIZE]
的固定成员,您不再需要为整个数组分配内存,而只需为其中的元素分配内存,因为它们在这种情况下是灵活的.
当你malloc
any sort of dynamic array, it is safe to always check the return value of the void*
pointer returned from malloc
. Additionally, when you free
每个元素的时候,再把每个成员都设置成NULL
就更安全了,防止指针再次访问内存。
通过这段代码说明:
#include <stdio.h>
#include <stdlib.h>
#define ARR_SIZE 100
typedef struct {
int data1;
int data2;
int data3;
// ...etc...
} container_t;
int
main(void) {
container_t *arr[ARR_SIZE];
int i;
for (i = 0; i < ARR_SIZE; i++) {
arr[i] = malloc(sizeof(container_t));
if (arr[i] == NULL) {
printf("Malloc Problem here\n");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < ARR_SIZE; i++) {
if (arr[i]) {
free(arr[i]);
arr[i] = NULL;
}
}
return 0;
}
When I malloc() something, I'm reserving memory space on the heap, right?
别说了,堆是一个实现细节。您正在动态分配内存。您还负责再次动态释放它。
But my container* arr[ARR_SIZE]; call
这不是调用,而是声明。
creates the array on the stack.
也别说了,栈也是一个实现细节
您正在声明一个具有自动作用域的局部变量(这里是一个指针数组),编译器负责管理它的内存和生命周期。
它的生命周期不是动态的,因为一旦到达封闭块末尾的 }
,它就变得无法访问,因此编译器可以确定地为您处理它。
所有局部变量在此处的行为相同:
{
int i;
double d[2];
} /* neither i nor d are reachable after here,
so the compiler takes care of releasing any storage */
So... the array of container* pointers exists on the stack,
考虑更简单的声明 container c;
。这是一个具有自动作用域的局部变量,编译器会按照讨论的方式处理(解除)分配。
现在考虑 container *p;
。这是也是一个具有自动作用域的局部变量,但该变量是一个指针。您仍然需要手动将其指向 ,如果您指向的对象是从 malloc
返回的,则您需要自己 free
。
进一步考虑一个简单的数组container a[2];
。现在你有一个本地 array 具有自动范围,包含你的 container
类型的两个实例。这两个实例具有相同的生命周期,它仍然由编译器管理。您可以访问 a[0]
和 a[1]
,几乎所有其他内容都是非法的。
and all of those container* pointers point to a container struct on the heap. Is that correct?
没有。最后考虑container* ap[2]
。同样,我们有一个具有自动作用域的本地数组,包含两个 指针 。指针的类型是 pointer-to-container,pointers 的生命周期由编译器管理。然而,指针还没有指向任何东西,你有责任决定将它们指向什么,并弄清楚指向的生命周期-在事情有。
一旦你这样做了
ap[i] = malloc(sizeof(*ap[i]));
(你不需要转换,避免显式命名类型通常更安全,以防你稍后更改它并分配错误的大小),你已经分配了一个你负责的对象释放。您还将数组中的一个指针指向该对象,但这并不会以某种方式改变指针本身的生命周期。该数组像往常一样超出范围无论它的指针指向什么地方。
我正在努力学习 malloc() / free() 的 C 语言规则。考虑下面的代码,它运行得很好。 (在 Linux 上,使用 GCC 编译。)具体来说,我想知道 arr
数组。我知道你必须为数组 中 中的所有结构元素分配 malloc... 但为什么你不必为数组分配 malloc 本身?
#include<stdio.h>
#include<stdlib.h>
#define ARR_SIZE 100
typedef struct containerStruct{
int data1;
int data2;
int data3;
// ...etc...
} container;
int main(){
container* arr[ARR_SIZE]; // Don't I have to malloc this?
int i;
for(i=0; i<ARR_SIZE; i++){
arr[i] = (container*) malloc (sizeof(container)); // I get why I have to malloc() here
}
...do stuff...
for(i=0; i<ARR_SIZE; i++){
free(arr[i]); // I get why I have to free() here
}
// Don't I have to free(arr) ?
return 0;
}
我猜 container* arr[ARR_SIZE];
行告诉编译器它需要知道的所有信息,以便在内存中为数组划分出 space,这就是这段代码有效的原因。
但不知何故,它仍然 "feel" 不对。当我 malloc() 某些东西时,我在堆上保留内存 space ,对吧?但是我的 container* arr[ARR_SIZE];
调用在堆栈上创建了数组。所以......容器*搬运工数组存在于堆栈中,所有这些容器*指针都指向堆上的容器结构。对吗?
container* arr[ARR_SIZE];
告诉 编译器 分配 ARR_SIZE
类型 container*
元素的数组] 并且编译器相应地分配内存。
换句话说,这类似于说 int x[5] = 0;
,其中编译器为 5 int
的数组分配了足够的 space。在您的情况下,编译器为 ARR_SIZE
个指针分配了足够的 space,container*
就是这样。现在,由您决定让这些指针 指向 有效的内存位置。为此,您可以
- 使用内存分配器函数(如您所述,它从 堆 分配内存)
- 分配相同类型的其他变量的地址(无论如何不需要从堆中分配)。
所以,最重要的是,您不需要为 数组分配任何内存。对于每个单独的数组元素,您需要使用内存分配器函数分配内存,因为您希望每个元素指向 valid 内存。
在您的 arr
声明下方,您有以下内容:
int i;
其中保留了足够 space (可能在 "stack" 上) 来存储一个 int
。这 "feel" 你也觉得不对吗?
arr
的声明没有什么不同。编译器为 container *
的 ARR_SIZE
元素数组分配足够的 space (可能在 "stack")。
您可以选择以下选项之一:
int i;
container** arr = malloc(sizeof(container*)*ARR_SIZE);
for (i=0; i<ARR_SIZE; i++)
arr[i] = malloc(sizeof(container));
// do stuff...
for(i=0; i<ARR_SIZE; i++)
free(arr[i]);
free(arr);
int i;
container* arr[ARR_SIZE];
for (i=0; i<ARR_SIZE; i++)
arr[i] = malloc(sizeof(container));
// do stuff...
for(i=0; i<ARR_SIZE; i++)
free(arr[i]);
container arr[ARR_SIZE];
// do stuff...
由于ARR_SIZE
是常数,你不妨选择最后一个选项。
由于 ARR_SIZE
是动态数组 *arr[ARR_SIZE]
的固定成员,您不再需要为整个数组分配内存,而只需为其中的元素分配内存,因为它们在这种情况下是灵活的.
当你malloc
any sort of dynamic array, it is safe to always check the return value of the void*
pointer returned from malloc
. Additionally, when you free
每个元素的时候,再把每个成员都设置成NULL
就更安全了,防止指针再次访问内存。
通过这段代码说明:
#include <stdio.h>
#include <stdlib.h>
#define ARR_SIZE 100
typedef struct {
int data1;
int data2;
int data3;
// ...etc...
} container_t;
int
main(void) {
container_t *arr[ARR_SIZE];
int i;
for (i = 0; i < ARR_SIZE; i++) {
arr[i] = malloc(sizeof(container_t));
if (arr[i] == NULL) {
printf("Malloc Problem here\n");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < ARR_SIZE; i++) {
if (arr[i]) {
free(arr[i]);
arr[i] = NULL;
}
}
return 0;
}
When I malloc() something, I'm reserving memory space on the heap, right?
别说了,堆是一个实现细节。您正在动态分配内存。您还负责再次动态释放它。
But my container* arr[ARR_SIZE]; call
这不是调用,而是声明。
creates the array on the stack.
也别说了,栈也是一个实现细节
您正在声明一个具有自动作用域的局部变量(这里是一个指针数组),编译器负责管理它的内存和生命周期。
它的生命周期不是动态的,因为一旦到达封闭块末尾的 }
,它就变得无法访问,因此编译器可以确定地为您处理它。
所有局部变量在此处的行为相同:
{
int i;
double d[2];
} /* neither i nor d are reachable after here,
so the compiler takes care of releasing any storage */
So... the array of container* pointers exists on the stack,
考虑更简单的声明 container c;
。这是一个具有自动作用域的局部变量,编译器会按照讨论的方式处理(解除)分配。
现在考虑 container *p;
。这是也是一个具有自动作用域的局部变量,但该变量是一个指针。您仍然需要手动将其指向 ,如果您指向的对象是从 malloc
返回的,则您需要自己 free
。
进一步考虑一个简单的数组container a[2];
。现在你有一个本地 array 具有自动范围,包含你的 container
类型的两个实例。这两个实例具有相同的生命周期,它仍然由编译器管理。您可以访问 a[0]
和 a[1]
,几乎所有其他内容都是非法的。
and all of those container* pointers point to a container struct on the heap. Is that correct?
没有。最后考虑container* ap[2]
。同样,我们有一个具有自动作用域的本地数组,包含两个 指针 。指针的类型是 pointer-to-container,pointers 的生命周期由编译器管理。然而,指针还没有指向任何东西,你有责任决定将它们指向什么,并弄清楚指向的生命周期-在事情有。
一旦你这样做了
ap[i] = malloc(sizeof(*ap[i]));
(你不需要转换,避免显式命名类型通常更安全,以防你稍后更改它并分配错误的大小),你已经分配了一个你负责的对象释放。您还将数组中的一个指针指向该对象,但这并不会以某种方式改变指针本身的生命周期。该数组像往常一样超出范围无论它的指针指向什么地方。