我一直在尝试使用C语言的结构,指针和内存。 我已经创建了这个结构
typedef struct {
int id;
char *name;
} Object;
这是构造函数
void object_ctor(Object *o, int id, char *name)
{
o->id = id;
o->name = malloc(sizeof(name));
if(sizeof(o->name)!=sizeof(name))
{
o->name=NULL;
}
else
{
strcpy(o->name, name);
}
}
这是o1的去壳
char tmp_name[] = "Hello 1";
Object o1;
object_ctor(&o1, 1, tmp_name);
这里是析构函数
void object_dtor(Object *o)
{
if(o->name != NULL)
{
free(o->name);
o->name = NULL;
}
}
打印对象
void print_object(Object *o)
{
printf("ID: %d, NAME: %s\n", o->id, o->name);
}
通话副本
Object copy;
print_object(object_cpy(©, &o1));
我正在尝试创建一个结构到另一个结构的副本(我已经构造了它们)。
Object *object_cpy(Object *dst, Object *src)
{
if(src!=NULL)
{
const size_t len_str=strlen(src->name)+1;
dst->name = malloc(10000000);
dst->id = src->id;
strncpy (dst->name, src->name,len_str);
}
if (strcmp(dst->name,src->name)!=0)
{
dst->name = NULL;
}
return dst;
}
但是当我尝试同时释放副本和原始src时,出现了分段错误。我一直试图通过gdb运行它,它说我要释放两次相同的内存,所以我认为复制代码是错误的,但是我不知道在哪里。
这是给我分段错误的代码
printf("\nCOPY EMPTY\n");
object_dtor(©);
o1.id = -1;
free(o1.name);
o1.name = NULL;
object_cpy(©, &o1);
print_object(©);
print_object(&o1);
我包括这些库
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
我正在使用std=c99
标志进行编译。
答案 0 :(得分:1)
这里至少有一个问题:
void object_ctor(Object *o, int id, char *name)
{
o->id = id;
o->name = malloc(sizeof(name));
if (sizeof(o->name) != sizeof(name))
{
o->name = NULL;
}
else
{
strcpy(o->name, name);
}
}
sizeof(name)
不是name
指向的字符串的长度。您需要strlen(name) + 1
(对于NUL终止符为+1)。
您的测试if (sizeof(o->name) != sizeof(name))
是毫无意义的,我不确定您要在这里实现什么。
您可能想要这样:
void object_ctor(Object *o, int id, char *name)
{
o->id = id;
o->name = malloc(strlen(name) + 1);
if (o->name != NULL)
strcpy(o->name, name);
}
object_cpy
中存在类似的问题:
strncpy
strcmp(dst->name, src->name)
您可能想要这样:
Object *object_cpy(Object *dst, Object *src)
{
if (src != NULL)
{
const size_t len_str = strlen(src->name) + 1;
dst->name = malloc(len_str);
if (dst->name != NULL)
{
dst->id = src->id;
strcpy(dst->name, src->name);
}
}
return dst;
}
通过这些更正,以下代码可以正常工作:
int main()
{
char tmp_name[] = "Hello 1";
Object o1, copy;
object_ctor(&o1, 1, tmp_name);
object_cpy(©, &o1);
print_object(©);
print_object(&o1);
object_dtor(&o1);
object_dtor(©);
}
答案 1 :(得分:0)
如果这不能直接解决您的问题,请告诉我如何组织代码,以避免像您这样的内存问题。
首先,它们全部围绕结构解析。 对于每个结构,如果需要,我都会执行一个“构造函数”和一个“析构函数”。
构造函数的目的仅仅是将结构设置为一致状态。它永远不会失败(这意味着任何可能失败的代码(例如malloc)都不应位于构造函数中)。 析构函数的目的是清理结构。
我喜欢使用的一个小技巧是将构造函数放在宏中,使我能够执行类似“ Object var = OBJET_CONSTRUCTOR”的操作。 当然,这不可能总是,要由您来保持心意。
对于您的代码,可能是:
typedef struct {
int id;
char *name;
} Object;
#define OBJECT_CONSTRUCTOR {.id = -1,\ \\ Assuming -1 is relevant in your case, like an error code or a bad id value. Otherwise, it's useless.
.name = NULL}
void Object_Constructor(Object *self)
{
Object clean = OBJECT_CONSTRUCTOR;
*self = clean;
}
void Object_Destructor(Object *self)
{
free(self->name);
}
我们在这里。 如何使用它很简单:您总是从构造函数开始,而总是以析构函数结束。这就是为什么在析构函数中将char指针“ name”设置为NULL没用的原因,因为构造函数的任何其他函数都不应使用它。
现在,您可以具有“初始化”功能。您可以执行简单的初始化(这是您的构造函数),也可以执行副本初始化等 请记住,该结构已被调用到构造函数中。如果不是的话,那是开发人员的错,您不必计较。
在出现错误的情况下,一种不错的行为是不修改结构。 结构要么成功地进行了彻底修改,要么根本没有修改。 对于可能在很多时候失败的复杂结构,您可以通过在最后“交换”结果来实现。
void Object_Swap(Object *first, Object *second)
{
Object tmp = OBJECT_CONSTRUCTOR;
tmp = *fisrt;
*first = *second;
*second = tmp;
}
bool Object_InitByPlainList(Object *self, int id, consr char *name)
{
Object newly = OBJECT_CONSTRUCTOR;
bool returnFunction = false;
newly.id = id;
if (!(newly.name = strdup(name))) {
printf("error : %s : strdup(name) : name='%s', errno='%s'.\n", __func__, name, strerror(errno));
goto END_FUNCTION;
}
// Success !
Object_Swap(self, &newly);
returnFunction = true;
/* GOTO */END_FUNCTION:
Object_Destructor(&newly);
return (returnFunction);
}
乍看之下似乎过于复杂,但是该组织使您可以添加更多未来步骤“可能会失败”。
现在,您甚至可以执行以下操作:
bool Object_InitByCopy(Object *dst, Object *src)
{
return (Object_InitByPlainList(dst, src->id, src->name));
}
您要做的就是在文档中说:
仅此而已。您可以添加任何您想要的“ Object_ *”函数,例如:
void Object_Print(const Object *self)
{
printf("ID: %d, NAME: %s\n", self->id, self->name);
}
希望这个组织能解决您的记忆问题。
一个例子:
int main(void)
{
Object test = OBJECT_CONSTRUCTOR;
Object copy = OBJECT_CONSTRUCTOR;
if (!Object_InitByPlainList(&test, 1, "Hello World !")) {
// The function itself has logged why it has fail, so no need to add error printf here
return (1);
}
Object_Print(&test);
if (!Object_Copy(©, &test)) {
return (1);
}
Object_Destructor(&test);
Object_Destructor(©);
return (0);
}