c malloc 结构数组
c malloc array of struct
到目前为止,我已经处理了一些指针和结构,但我不确定如何在运行时分配结构数组 - 见下文。
N.B。 "user_size" 在运行时初始化。
typedef struct _COORDS
{
double x;
double y;
double area;
double circumference;
int index;
wchar_t name[16];
} COORDS, *PCOORDS;
PCOORDS pCoords = (PCOORDS)malloc(sizeof(COORDS)* user_size);
// NULL ptr check omitted
在那之后,我可以像访问普通的整数数组一样访问 pCoords[0]
到 pCoords[user_size-1]
吗?
更重要的是:我不明白编译器如何将结构的布局叠加到分配的内存上?它甚至必须还是我想得太多了?
你可能想多了。编译器不会 "superimpose" malloc
内存中的任何内容 - 那只是一堆字节。
但是,指针在 C 中是 typed,指针的类型决定了当指针被取消引用时内存如何被 解释或用于指针算术。编译器知道结构的内存布局。每个字段都有一个定义的大小和一个偏移量,并且结构的整体大小也是已知的。
在您的例子中,表达式 pCoords[i].area = 42.0
等同于
char *pByte = (char*)pCoords + sizeof(COORDS) * i + offsetof(COORDS, area);
double *pDouble = (pDouble*)pByte;
*pDouble = 42.0;
编译器不会将结构强加到内存上——您告诉它这样做!
通过将一个元素的索引乘以其总大小来访问结构数组。例如pCoords[3]
在内存中是"at"pCoords + 3*sizeof(COORDS)
结构成员通过其 偏移量 访问(这是根据它前面的元素的大小计算的,并考虑了填充)。因此,成员 x
位于距其容器起点的偏移量 0
处,pCoords
加上数组元素索引的 sizeof(COORDS)
倍; y
之后是 sizeof(x)
。
既然你告诉编译器(1)你想要一个连续的内存块,其大小是单个COORD
的user_size
倍],和(2)然后通过pCoords[2].y
访问它,它所要做的就是乘和加,然后读取该内存地址中的值(字面意思)。由于 y
的类型是 double
,它读取原始字节 并将其解释为 一个双精度字节。通常,它做对了。
唯一可能出现的问题是当您有多个 指针 指向同一内存区域时。这可能意味着地址的原始字节 "at" 可能需要解释为不同的类型(例如,当一个指针告诉它期望一个 int
而另一个指针告诉它期望一个 double
)。
前提是有效范围实际上是 0
..user_size - 1
,您的代码没问题。
到目前为止,我已经处理了一些指针和结构,但我不确定如何在运行时分配结构数组 - 见下文。
N.B。 "user_size" 在运行时初始化。
typedef struct _COORDS
{
double x;
double y;
double area;
double circumference;
int index;
wchar_t name[16];
} COORDS, *PCOORDS;
PCOORDS pCoords = (PCOORDS)malloc(sizeof(COORDS)* user_size);
// NULL ptr check omitted
在那之后,我可以像访问普通的整数数组一样访问 pCoords[0]
到 pCoords[user_size-1]
吗?
更重要的是:我不明白编译器如何将结构的布局叠加到分配的内存上?它甚至必须还是我想得太多了?
你可能想多了。编译器不会 "superimpose" malloc
内存中的任何内容 - 那只是一堆字节。
但是,指针在 C 中是 typed,指针的类型决定了当指针被取消引用时内存如何被 解释或用于指针算术。编译器知道结构的内存布局。每个字段都有一个定义的大小和一个偏移量,并且结构的整体大小也是已知的。
在您的例子中,表达式 pCoords[i].area = 42.0
等同于
char *pByte = (char*)pCoords + sizeof(COORDS) * i + offsetof(COORDS, area);
double *pDouble = (pDouble*)pByte;
*pDouble = 42.0;
编译器不会将结构强加到内存上——您告诉它这样做!
通过将一个元素的索引乘以其总大小来访问结构数组。例如pCoords[3]
在内存中是"at"pCoords + 3*sizeof(COORDS)
结构成员通过其 偏移量 访问(这是根据它前面的元素的大小计算的,并考虑了填充)。因此,成员 x
位于距其容器起点的偏移量 0
处,pCoords
加上数组元素索引的 sizeof(COORDS)
倍; y
之后是 sizeof(x)
。
既然你告诉编译器(1)你想要一个连续的内存块,其大小是单个COORD
的user_size
倍],和(2)然后通过pCoords[2].y
访问它,它所要做的就是乘和加,然后读取该内存地址中的值(字面意思)。由于 y
的类型是 double
,它读取原始字节 并将其解释为 一个双精度字节。通常,它做对了。
唯一可能出现的问题是当您有多个 指针 指向同一内存区域时。这可能意味着地址的原始字节 "at" 可能需要解释为不同的类型(例如,当一个指针告诉它期望一个 int
而另一个指针告诉它期望一个 double
)。
前提是有效范围实际上是 0
..user_size - 1
,您的代码没问题。