我想问一个简单的问题。请考虑附带的代码。在main函数中,通过ctor1或ctor 2以两种不同的方式构建指向结构的指针。在这两种情况下,无论我使用哪种构造函数,程序都可以工作。
ctor1工作的原因是struct实例的内存是在功能框外部(即在堆中)分配的。因此,在ctor1终止后,它将在主函数中可用。
我的问题归结为ctor2功能。据我所知,局部变量“myPtr foo”预计会在函数端被销毁。因此,“那个”指针从现在开始应该指向什么。然而,在执行了该程序之后,我发现两个构造函数都能完美地工作。
显然,有一个微妙的细节让我望而却步。你能解释为什么函数ctor2有效吗? 提前谢谢!
#include <stdio.h>
#include <malloc.h>
int _method(void) {
return 0;
}//_foo
typedef struct vTable {
int (*method)(void);
} myPtr;
myPtr *ctor1(void) {
myPtr *foo;
foo = (myPtr*)malloc(1 * sizeof(myPtr));
foo->method = &_method;
return foo;
}//ctor1
void ctor2(myPtr *that) {
myPtr foo = { &_method };
that = &foo;
return;
// having reached the function end "foo" is destroyed
// and "that" should point to nothing, supposedly
}//ctor2
int dtor(myPtr *foo) {
free(foo);
foo->method = NULL;
foo = NULL;
return 0;
}//dtor
int main(void) {
myPtr *vPtr;
// it works as expected
vPtr = ctor1();
printf("%p\n\n", vPtr); // 003E0F68
dtor(vPtr);
// it works surprisingly enough
ctor2(vPtr);
printf("%p\n", vPtr); // 003E0F68
printf("%p\n", vPtr); // 003E0F68
// it keeps on working
printf("%p\n", vPtr); // 003E0F68
dtor(vPtr);
return 0;
}//main
答案 0 :(得分:1)
代码void ctor2(myPtr *that)
将that
声明为指向myPtr
类型的对象的参数。参数按值传递,因此参数that
只是传递的内容的副本。更改that
不会改变传递的内容。
如果要将指针的值更改为myPtr
,则必须将指针传递给指向myPtr
的指针:
void ctor2(myPtr **that)
然后你可以用:
改变它*that = malloc(…);
答案 1 :(得分:1)
这里有几个问题,让我们一个接一个地看看。
首先,在ctor2
函数中:
void ctor2(myPtr *that) {
myPtr foo = { &_method };
that = &foo;
return;
}//ctor2
此函数实际上是通过值接收指向myPtr的指针并在本地修改它以指向函数中堆栈上分配的内容。这对传入的指针有效。如果你想修改传入的指针,你会传入一个双指针并取消引用它:
void ctor2(myPtr **that) {
//malloc foo
*that = foo;
return;
}
其次,因为您从未通过调用ctor2
来修改vPtr,所以对dtor
的第二次调用释放已经释放的内存,这是通常导致崩溃的未定义行为。我很惊讶它没有在你的系统上崩溃,但这是UB的事情,你永远不会知道。
第三,您想要模仿的行为是:
/* constructor */
void Shape_ctor(Shape * const me, int16_t x, int16_t y) {
static struct ShapeVtbl const vtbl = { /* vtbl of the Shape class */
&Shape_area_,
&Shape_draw_
};
me->vptr = &vtbl; /* "hook" the vptr to the vtbl */
me->x = x;
me->y = y;
}
不同之处在于,在这种情况下,ShapeVtbl
结构是静态分配的。这没关系,因为它只指向函数,这些函数不会从对象实例更改为对象实例。但是静态分配允许它在类似的函数中分配并分配给对象。
答案 2 :(得分:0)
为了扩大Eric Postpischil的优秀answer,请考虑,
void foo( int i ) { i++; }
此函数更改传递的值,但该值不是调用时原始文件的副本,
int j=8;
foo(j);
你不会期望j
改变,对吧?
也是如此
void ctor2(myPtr *that) { // my version
that = NULL;
}
that
是在调用时传递的参数的副本,
ctor2(vPtr);
由于vPtr
没有变化,您的程序会打印...其值不变。
ctor2
可以通过that
更改指向的任何值,但对参数本身的任何更改都只会产生局部效果。
您的计划中还有其他错误,正如其他答案所指出的那样。但是为什么ctor2
&#34;工作的答案和#34;基本上它没有做任何事情。