我为我的项目编写了以下代码。代码分散在各种文件中并且很长,因此我发布了最小代码。
#include<stdio.h>
#include<stdbool.h>
struct TwoPoint
{
int width;
int value;
};
struct Module
{
int categ;
void *ptr;
};
struct Rect
{
struct TwoPoint val;
struct TwoPoint val_new;
bool is_changed;
};
struct S
{
int numInstances;
struct Module instances[20];
struct Rect RectList[40];
int numRect;
}s1;
struct Test
{
int categ;
struct Rect state;
};
struct TwoPoint initPVal(int v,int w)
{
struct TwoPoint temp;
temp.value=v;
temp.width=w;
return temp;
}
int getValue(struct TwoPoint *b)
{
return (b->value);
}
struct TwoPoint get(struct Rect *r)
{
return (r->val);
}
void initialize()
{
s1.numInstances=0;
s1.numRect=0;
}
void addRect(struct Rect *r)
{
if(s1.numRect<40)
{
s1.RectList[s1.numRect].val=r->val;
s1.RectList[s1.numRect].val_new=r->val_new;
s1.RectList[s1.numRect].is_changed=r->is_changed;
s1.numRect++;
}
}
struct Rect initRect(struct TwoPoint initval)
{
struct Rect temp;
struct TwoPoint tempP;
tempP=initPVal(0,0);
temp.val=initval;
temp.val_new=tempP;
temp.is_changed=false;
addRect(&temp);
return temp;
}
void copy(struct Rect *r)
{
if(r->is_changed)
{
r->val= r->val_new;
r->is_changed=false;
}
}
void copyRect()
{
int i=0;
for(i=0;i<s1.numRect;i++)
{
copy(&s1.RectList[i]);
}
}
void setInstance(struct Module *m)
{
s1.instances[s1.numInstances].categ=m->categ;
s1.instances[s1.numInstances].ptr=m->ptr;
s1.numInstances++;
if (s1.numInstances >= 20)
{
printf("Too many instances");
}
}
void setModule(struct Test *t)
{
struct Module m;
m.categ=t->categ;
m.ptr=&t;
setInstance(&m);
}
void init(struct Test *t)
{
t->categ=2;
struct Rect tr;
struct TwoPoint tb1=initPVal(0,5);
tr=initRect(tb1);
t->state=tr;
}
void actions(struct Test *t)
{
struct TwoPoint tb=get(&t->state);
int y=getValue(&tb);
printf("%d\n",y);
unsigned int x=getValue(&tb);
printf("%u\n",x);
switch(y)
{
....
}
}
void initS()
{
init(s1.instances[0].ptr);
}
void act()
{
actions(s1.instances[0].ptr);
}
void setup()
{
struct Test t;
initialize();
init(&t);
setModule(&t);
}
void run()
{
initS();
act();
copyRect();
}
int main()
{
printf("foo\n");
setup();
printf("bar\n");
run();
return 0;
}
有两个错误:
答案 0 :(得分:2)
问题是:
void setup()
{
struct Test t;
initialize();
init(&t);
setModule(&t);
}
将Test
结构分配为本地堆栈变量,然后将其地址分配给稍后访问的某个变量。访问此变量的下一次是(init
):
void init(struct Test *t)
{
t->categ=2;
struct Rect tr;
struct TwoPoint tb1=initPVal(0,5);
tr=initRect(tb1);
t->state = tr;
}
此时指针指向已超出范围的变量,导致未定义的行为。实际发生的是由于尝试的结构分配,堆栈被粉碎。这就是为什么它也很难获得回溯的原因。
一种解决方案是使用malloc
分配内存,如下所示:
void setup()
{
struct Test * t = malloc(sizeof (struct Test));
initialize();
init(t);
setModule(t);
}
存在另一个问题,即setModule
中的语义错误:
void setModule(struct Test *t)
{
struct Module m;
m.categ=t->categ;
m.ptr=&t;
setInstance(&m);
}
m.ptr=&t
实际应该是m.ptr = t
。打算指定一个指向Test
结构的指针。相反,发生的事情是指定了一个指向Test
结构(指向Test
结构的双指针)指针的堆栈变量的地址。
答案 1 :(得分:1)
我假设您显示run()
调用actions()
的位置,实际上是调用act()
,因为前一个函数需要一个参数。
在setModule()
中,您有
m.ptr=&t;
其中t
已经是指向struct Test
的指针。所以你在m.ptr
中存储的是指向结构的指针。在act()
中,将此存储的指针传递给actions()
,它指向一个结构的指针,而不是指向结构的指针。因此,当函数取消引用指针并将结果视为struct Test
时,它会得到谁知道什么。
最有可能的是,您只想将setModule()
中的行更改为
m.ptr=t;
因为t
已经是指针。但也许有一些原因你真的想要一个指针指针,在这种情况下你需要更改使用指针正确使用它的代码。这里的一个问题是编译器无法帮助您确保类型安全,因为您将指针存储为void *
并隐式将其转换为其他类型。
作为旁注,您似乎比我想象的那样使用&
运算符。在我看来,你的函数是只读的,例如getValue()
,应该只是一个struct参数,而不是一个结构的指针,然后你就不需要那么多地获取变量的地址。但也许这是一个品味问题。