如何在C中使用动态分配的内存



我一直在Scilab/Xcos(Matlab/Simulink的开源变体(中使用C语言开发一个块。为此,Scilab/Xcos提供了一个名为CBLOCK4的特殊块。一旦我将这个块放入模拟中,就会自动生成一个C语言存根。存根的一部分是实现块行为的函数的模板。此函数在其参数中接受指向scicos_block结构的指针:

typedef struct {
int nevprt;
voidg funpt ;
int type;
int scsptr;
int nz;
double *z;
int noz;
int *ozsz;
int *oztyp;
void **ozptr;
int nx;
double *x;
double *xd;
double *res;
int nin;
int *insz;
void **inptr;
int nout;
int *outsz;
void **outptr;
int nevout;
double *evout;
int nrpar;
double *rpar;
int nipar;
int *ipar;
int nopar;
int *oparsz;
int *opartyp;
void **oparptr;
int ng;
double *g;
int ztyp;
int *jroot;
char *label;
void **work;
int nmode;
int *mode;
} scicos_block;

项CCD_ 2可能旨在用于存储另一地址的地址,在该地址存储块的内部状态变量。我尝试使用work项目用法:来实现Scilab/Xcos块

#include "scicos_block4.h"
#define U  ((double *)GetRealInPortPtrs(block, 1))
#define Y  ((double *)GetRealOutPortPtrs(block, 1))
// parameters
#define Tu (GetRparPtrs(block)[0])
#define Td (GetRparPtrs(block)[1])
#define T  (GetRparPtrs(block)[2])

void Ramp(scicos_block *block, int flag)
{

double *target;
double *inputDelta;
double *out;
if(flag == 4) 
{
/* init */
if((*(block->work) = (double *)scicos_malloc(sizeof(double)*3)) == NULL)
{
set_block_error(-16);
return;
}

target      = (double*)(*(block->work));
inputDelta  = (double*)(*(block->work + 1));
out         = (double*)(*(block->work + 2));
*target     = 0;
*inputDelta = 0;
*out        = 0; 
}
else if(flag == 1) 
{
/* output computation */ 
if(U[0] != *target)
{
*target = U[0];

if(*target - Y[0] < 0)
{
*inputDelta = Y[0] - *target;
}
else
{
*inputDelta = *target - Y[0];
}
}

if(*target > Y[0])
{
*out += *inputDelta*T/Tu;
if(*out > *target)
{
*out = *target;
}
}
else if(*target < Y[0])
{
*out -= *inputDelta*T/Td;
if(*out < *target)
{
*out = *target;
}
}

Y[0] = *out;  
} 
else  if (flag == 5) 
{
/* ending */
scicos_free(*(block->work));
}
}

我能够成功编译包含此代码的块,但如果我启动模拟,它会崩溃。我对内存的动态分配以及如何处理内存有疑问。

请有人看看我的代码(即if主体中带有flag==4的部分(,告诉我我做错了什么吗?

此行

target      = (double*)(*(block->work));

是正确的,但是这些线

inputDelta  = (double*)(*(block->work + 1));
out         = (double*)(*(block->work + 2));

是错误的。

(*(block->work)将为您提供指向三个malloc’ed double中的第一个的指针。

然而,你不会像以前那样得到下一个替身——你加一个太早了。更改为:

(double*)(*(block->work + 1));   // Wrong !!
(double*)(*(block->work)) + 1;   // Correct !!
^^^^^^^^^^^^^^^^^^^^^^^^^   ^
Get pointer to malloced     Then add 1 to get to the second malloc'ed double
memory (i.e. the first
malloc'ed double) and use 
it as a double-pointer

或者简单地做:

target      = (double*)(*(block->work));
inputDelta  = target + 1;
out         = target + 2;

BTW:你不需要所有的选角。把它取下来。

编辑:在评论中,OP告诉我们它仍然崩溃

发布的代码在调用Ramp之前没有告诉我们block->work是否已初始化。如果在此之前未初始化,则执行*(block->work)将是非法的,并可能导致崩溃。

因此,也许代码缺少了类似以下内容:

/* init */
block->work = malloc(sizeof *block->work);  // Add this line
if((*(block->work) = (double *)scicos_malloc(sizeof(double)*3)) == NULL)

正如用户4386427的回答中所提到的,(double*)(*(block->work + 1))应该是(double*)(*(block->work)) + 1。如果sizeof(double)sizeof(void*)具有不同的值,这一点尤其重要。(在典型的64位系统上,它们的值相同,但在典型的32位系统上它们的值不同。(

另一个严重的问题是,当flag == 1targetinputDeltaout变量包含未初始化的值但正在被取消引用时。变量需要在else if (flag == 1)块中分配,然后才能以与if (flag == 4)块中相同的方式解引用。

我认为如果定义struct类型来保存工作数据,代码会更干净:

struct Ramp_work
{
double target;
double inputDelta;
double out;
};
void Ramp(scicos_block *block, int flag)
{
struct Ramp_work *work;
if (flag == 4)
{
/* init */
work = scicos_malloc(sizeof(*work));
*block->work = work;
if (work == NULL)
{
set_block_error(-16);
return;
}
work->target = 0;
work->inputDelta = 0;
work->out = 0;
}
else if (flag == 1)
{
/* output computation */
work = *block->work;
if (U[0] != work->target)
{
/* etc. */
}
/* etc. */
}
else if (flag == 5)
{
/* ending */
scicos_free(*block->work);
}
}

相关内容

  • 没有找到相关文章