C 非动态阵列何时可用';结构中的d

C 非动态阵列何时可用';结构中的d,c,memory-management,struct,malloc,free,C,Memory Management,Struct,Malloc,Free,我有以下struct typedef struct { int id; double c[2]; double p[4][2]; } Detection; 这是它的构造函数 Detection* create_detection(int i) { Detection* detection = (Detection*) malloc(sizeof(Detection)); detection->id = i; return detectio

我有以下
struct

typedef struct  {
    int id;
    double c[2];
    double p[4][2];
} Detection;
这是它的构造函数

Detection* create_detection(int i) {
    Detection* detection = (Detection*) malloc(sizeof(Detection));
    detection->id = i;
    return detection;
}
如您所见,结构本身是动态分配的。我正试图为它编写一个析构函数,这就是我目前所拥有的

void destroy_detection(Detection* detection) {
    free(detection);
}
这也将免费
c
p

这也将免费
c
p

数组
c
p
是静态分配的,这意味着将为您管理内存;你不必担心


经验法则:调用
free()
的次数与调用
malloc()
的次数相同


在这里,动态分配内存一次,因此必须仅取消分配该动态内存一次。

这里只有一次分配。
c
p
字段没有单独的分配。一般规则是,每次调用
malloc
都必须通过调用
free
一对一进行平衡。编写的析构函数就是所需的全部。如果结构中有其他动态分配的指针,则可能需要额外的
free
调用

请注意,
c
p
字段具有固定大小,包括在
sizeof(Detection)
中。在C++领域中,可以有自己的构造函数,它们可以进行动态分配,但是它们也会从编译器在父析构函数中生成的代码中自动销毁。
C具有可变长度数组(VLA),但它们不能在结构中声明,只能在函数参数列表或函数内的块中声明。

C和
p
的内存在结构中内联分配。这是因为
c
p
作为数组而不是指针。如果在C中指针和数组不是一回事。如果将c和p定义为指针,那么在使用它们之前,您必须为它们分配和释放内存


造成混乱的原因是数组有时会衰减为指针,反之亦然。这方面的一个例子是
double*ptr=c
double*ptr=&c[0]
c
是一个数组)的等价性。指针衰减在访问数组时发生,在定义数组时不会发生。

我想明确说明其他答案中暗示的重要部分:

malloc不知道它为什么分配内存。

它接收字节数作为输入,并返回一个指针,该指针后面至少有那么多字节可寻址

在我的编译器/机器组合
sizeof(Detection)
88
。所以
malloc
只需在堆中分配88个ish字节,并返回指向它的指针。 程序员有责任以某种方式解释该内存(编译器有责任帮助以正确的方式在内存中布局结构成员,并生成适当的代码,给定指向内存的指针和成员名,它将计算内存中的适当偏移量以访问该成员数据)-在代码中,您将该地址分配给指向
检测
结构的指针。您也可以尝试将其分配给指向另一个结构的指针,根据结构大小和分配的内存量,它可能工作,也可能不工作(如程序崩溃和/或清除计算机上的所有数据)

因此,
malloc
,不知道它为包含数组的结构分配内存。它只分配连续的内存区域,如果编码正确(即传递给
malloc
)的大小正确),就足以包含
检测类型的结构

我们可以稍微修改一下您的代码(我有点作弊,因为在我的机器上,
long-long
double
的大小恰好相同,请不要这样做):

从内存中的值可以很容易地看到结构在内存中的布局,至少可以注意到数组嵌入到内存布局中

因此,
free
也完全不知道传递给它的指针的另一端是什么类型的结构。它只接收先前由
malloc
(a
void*
)返回的地址,并知道如何将其作为内存块(而不是某种类型的结构)释放。除了将内存标记为“未使用”之外,没有其他类型的“破坏”发生

我在
malloc
返回的地址之前添加了额外的16字节内存,以演示
free
如何知道要释放多少内存(顺便说一句,这完全取决于实现,您不应该以任何方式依赖它)。您可能会注意到,第一行中的
58
转换为十进制
88
——它是分配的内存大小


可以很容易地将
size+42
传递给
malloc
,它仍然是正确的程序,只会浪费内存。

请注意,给定的代码,例如
双c[2],例如
*(long-long*)(&detection->c[0])=0x1011121314151617违反了严格的别名,是未定义的行为。当然,不要这样做。我只是想证明内存只是一个内存,字节没有任何意义。它的解释取决于编写代码的人。
#include <stdlib.h>
#include <stdio.h>

typedef struct {
    int id;
    double c[2];
    double p[4][2];
} Detection;

int main()
{
    size_t size = sizeof(Detection);
    printf("sizeof(Detection) = %u\n", size);
    Detection *detection = malloc(size);
    detection->id = 0x01020304;
    *(long long *)(&detection->c[0]) = 0x1011121314151617;
    *(long long *)(&detection->c[1]) = 0x18191A1B1C1D1E1F;
    *(long long *)(&detection->p[0][0]) = 0x2021222324252627;
    *(long long *)(&detection->p[0][1]) = 0x28292A2B2C2D2E2F;
    *(long long *)(&detection->p[1][0]) = 0x3031323334353637;
    *(long long *)(&detection->p[1][1]) = 0x38393A3B3C3D3E3F;

    *(long long *)(&detection->p[2][0]) = 0x4041424344454647;
    *(long long *)(&detection->p[2][1]) = 0x48494A4B4C4D4E4F;
    *(long long *)(&detection->p[3][0]) = 0x5051525354555657;
    *(long long *)(&detection->p[3][1]) = 0x58595A5B5C5D5E5F;
}
0x01097008  01 00 00 00 58 00 00 00 4e 00 00 00 fd fd fd fd  ....X...N...ýýýý
======== detection starts here =========
0x01097018  04 03 02 01 cd cd cd cd 17 16 15 14 13 12 11 10  ....ÍÍÍÍ........
0x01097028  1f 1e 1d 1c 1b 1a 19 18 27 26 25 24 23 22 21 20  ........'&%$#"! 
0x01097038  2f 2e 2d 2c 2b 2a 29 28 37 36 35 34 33 32 31 30  /.-,+*)(76543210
0x01097048  3f 3e 3d 3c 3b 3a 39 38 47 46 45 44 43 42 41 40  ?>=<;:98GFEDCBA@
0x01097058  4f 4e 4d 4c 4b 4a 49 48 57 56 55 54 53 52 51 50  ONMLKJIHWVUTSRQP
0x01097068  5f 5e 5d 5c 5b 5a 59 58