我正在使用ANSI C代码,该代码由代码生成器生成,该代码生成器生成多层嵌套struct
以及带有参数列表的函数原型,这些参数列表使用指向顶层struct
的指针来传递或访问位于内部m struct
中的数据。
由于函数原型将指针传递给结构,因此应用程序必须分配内存以访问数据或将数据写入最内部的结构成员。 尝试为指向第二个嵌套结构的指针分配内存时,我看到了问题。
我收到的实际错误消息是非致命的运行时:"没有足够的空间将表达式转换为'指向结构数据的指针'。">
我没有显式转换任何内容,因此我怀疑malloc()
的实现可能有一个断言,当它看到某些条件时会生成消息。 这个错误的措辞可能特定于我的环境(我正在使用LabWindows/CVI(,但我也有兴趣听到其他ANSI C编译器的结果。
这是一个简化的、完整的代码片段,应该编译、构建和运行(直到错误位置,内联注释(
我将不胜感激对我的错误原因的评论,以及如何修复它的建议。
#include <ansi_c.h> //specific to LabWindows/CVI - change as needed for your environment
struct request
{
struct data *pData;
};
struct data
{
char *wsDate;
char *wsDuration;
char *wsFailures;
int __sizeM_Details;
struct details *M_Details;
};
struct details
{
char *wsStep;
char *wsTestDesc;
char *wsLowLim;
};
typedef struct request REQUEST; // from mtdf function prototype request argument (4)
typedef struct details DETAILS; // member of REQUEST - _ns1__MTDFData_MTDFDetail
void allocate(REQUEST *a, int numRecords);
void freemem(REQUEST *c, int numRecords);
int main(void)
{
REQUEST b, *pB;
pB = &b;
allocate(pB, 10);
freemem(pB, 10);
return 0;
}
void allocate(REQUEST *c, int numRecords)
{
DETAILS m_Param;
REQUEST b;
struct data d;
size_t size_c = sizeof(c);
c = malloc(size_c); //4 bytes
size_t size_c_data = sizeof(c->pData);
c->pData = malloc(size_c_data); //Breaks here - this is just a pointer,
//should it not just allocate 4 bytes
//and continue?
// Actual error message:
// "Not enough space for casting expression to 'pointer to struct data'."
c->pData->wsDate = calloc(80, sizeof(char));
c->pData->__sizeM_Details = numRecords;
c->pData->M_Details = calloc((numRecords + 1) , sizeof(m_Param));
}
void freemem(REQUEST *c, int numRecords)
{
free(c->pData->M_Details);
free(c->pData->wsDate);
free(c->pData);
free(c);
}
这里有几个基本问题:
-
在
allocate()
中,你malloc()
的所有内存在函数结束时都会丢失,因为你把它分配给一个局部变量,c
,它在函数结束时被销毁。切勿使用传递到函数中的具有自动存储持续时间的结构的地址。如果要传递具有自动存储持续时间的对象地址,则应为成员malloc()
内存,而不是结构本身,因为它显然已经具有内存。 -
然后,在
freemem()
中,您尝试free()
与b
关联的内存, 是一个具有自动存储持续时间的结构。您只能free()
已动态分配的内存。 -
你在
allocate()
中有一个奇怪的评论,"这只是一个指针,它不应该只分配 4 个字节并继续吗?如果你在一个有 32 位指针的系统上,那么这确实是你分配的,但c->pData
是一个指向struct data
的指针,看起来它在 32 位机器上需要 28 个字节,所以你应该为它分配超过 4 个字节。像c->pData->wsDate = ...
这样的行似乎表明你很清楚它是一个指向struct data
的指针,所以真的不清楚为什么你认为你应该只分配4个字节。当你为要指向的ANYTHING *
分配内存时,你需要为ANYTHING
分配足够的内存,而不是为ANYTHING *
分配足够的内存,即为它将指向的东西分配足够的内存。您首先尝试将内存分配给指针的事实证明您已经拥有指针的内存,否则您将无法做到这一点(当然,前提是您没有搞砸以前的一些分配(。 -
你从不检查
malloc()
和calloc()
的回报,你应该这样做。 -
以双下划线开头的名称始终保留用于实现,因此您应该调用
__sizeM_Details
其他名称。 -
根据定义,
sizeof(char)
是 1,因此永远不需要使用它。 -
目前还不清楚你为什么要为
numRecords + 1
struct details
分配内存,而不是像直觉上那样只分配numRecords
。也许您希望将最后一个设置为NULL
的哨兵值,但是如果您已经在结构中存储了记录数,那么这并不是真正必要的。
下面是你的代码应该是什么样子的:
#include <stdio.h>
#include <stdlib.h>
struct request {
struct data * pData;
};
struct data {
char * wsDate;
char * wsDuration;
char * wsFailures;
int sizeM_Details;
struct details * M_Details;
};
struct details {
char * wsStep;
char * wsTestDesc;
char * wsLowLim;
};
typedef struct request REQUEST;
typedef struct details DETAILS;
void allocate(REQUEST * c, const int numRecords);
void freemem(REQUEST * c);
int main(void)
{
REQUEST b;
allocate(&b, 10);
freemem(&b);
return 0;
}
void allocate(REQUEST * c, const int numRecords)
{
if ( !(c->pData = malloc(sizeof *c->pData)) ) {
perror("couldn't allocate memory for c->pData");
exit(EXIT_FAILURE);
}
if ( !(c->pData->wsDate = calloc(80, 1)) ) {
perror("couldn't allocate memory for c->pData->wsDate");
exit(EXIT_FAILURE);
}
if ( !(c->pData->M_Details = calloc(numRecords + 1,
sizeof(*c->pData->M_Details))) ) {
perror("couldn't allocate memory for c->pData->M_Details");
exit(EXIT_FAILURE);
}
c->pData->sizeM_Details = numRecords;
}
void freemem(REQUEST * c)
{
free(c->pData->M_Details);
free(c->pData->wsDate);
free(c->pData);
}
如果为b
分配自动存储是一个错误,并且您确实想要动态分配所有内容,包括您的struct request
,那么它应该如下所示:
#include <stdio.h>
#include <stdlib.h>
struct request {
struct data * pData;
};
struct data {
char * wsDate;
char * wsDuration;
char * wsFailures;
int sizeM_Details;
struct details * M_Details;
};
struct details {
char * wsStep;
char * wsTestDesc;
char * wsLowLim;
};
typedef struct request REQUEST;
typedef struct details DETAILS;
REQUEST * allocate(const int numRecords);
void freemem(REQUEST * c);
int main(void)
{
REQUEST * b = allocate(10);
freemem(b);
return 0;
}
REQUEST * allocate(const int numRecords)
{
REQUEST * c = malloc(sizeof *c);
if ( !c ) {
perror("couldn't allocate memory for c");
exit(EXIT_FAILURE);
}
if ( !(c->pData = malloc(sizeof *c->pData)) ) {
perror("couldn't allocate memory for c->pData");
exit(EXIT_FAILURE);
}
if ( !(c->pData->wsDate = calloc(80, 1)) ) {
perror("couldn't allocate memory for c->pData->wsDate");
exit(EXIT_FAILURE);
}
if ( !(c->pData->M_Details = calloc(numRecords + 1,
sizeof(*c->pData->M_Details))) ) {
perror("couldn't allocate memory for c->pData->M_Details");
exit(EXIT_FAILURE);
}
c->pData->sizeM_Details = numRecords;
return c;
}
void freemem(REQUEST * c)
{
free(c->pData->M_Details);
free(c->pData->wsDate);
free(c->pData);
free(c);
}