我有一些结构来存储不同类型的列表: typedef int db_int; typedef char db_string [DB_STRING_LEN];
struct List_db_int {
struct List_db_int *next;
struct List_db_int *prev;
db_int v;
};
struct List_db_string {
struct List_db_string *next;
struct List_db_string *prev;
db_string v;
};
struct List_db_void {
struct List_db_void *next;
struct List_db_void *prev;
};
我还有一个可以存储任何列表指针的联合:
union Uni_list {
struct List_db_int *db_type_int;
struct List_db_string *db_type_string;
struct List_db_void *db_type_void;
};
我想创建一个从列表中删除某些元素的函数,但我希望它是列表类型不可知的,所以我提出以下解决方案:
/*data is an array of pointers to begin of lists*/
union Uni_list *data;
struct List_db_void *last;
for (i = 0; i < ELEMENTS_; i++) {
last = data[i].db_type_void->next;
for (j = 0; j < HOW_MANY_ELEMENTS_REMOVE; j++) {
free_list(last, t->cols[i]/*type of column*/);
last = last->next;
}
data[i].db_type_void->next = last;
}
这是free_list函数: 空隙
free_list(struct List_db_void *elm, enum db_type type) {
switch(type) {
case db_type_int:
free((struct List_db_int*) elm);
break;
case db_type_string:
free((struct List_db_string*) elm);
break;
default:
/*Should not reach*/
return ;
break;
}
}
但它无法正常工作,当我尝试阅读修改过的列表时,我最终得到了:
*** Error in `./ppbase': free(): invalid pointer: 0x00007f84aa47f678 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x72ecf)[0x7f84aa14cecf]
/usr/lib/libc.so.6(+0x7869e)[0x7f84aa15269e]
/usr/lib/libc.so.6(+0x79377)[0x7f84aa153377]
./ppbase[0x402001]
./ppbase[0x40217e]
./ppbase[0x40273d]
/usr/lib/libc.so.6(__libc_start_main+0xf5)[0x7f84aa0fbbc5]
./ppbase[0x4009d9]
======= Memory map: ========
00400000-00404000 r-xp 00000000 08:04 10883382 /home/hafron/dev/ppbase/ppbase
00603000-00604000 rw-p 00003000 08:04 10883382 /home/hafron/dev/ppbase/ppbase
01797000-017b8000 rw-p 00000000 00:00 0 [heap]
7f84a9ec4000-7f84a9ed9000 r-xp 00000000 08:03 49858 /usr/lib/libgcc_s.so.1
7f84a9ed9000-7f84aa0d9000 ---p 00015000 08:03 49858 /usr/lib/libgcc_s.so.1
7f84aa0d9000-7f84aa0da000 rw-p 00015000 08:03 49858 /usr/lib/libgcc_s.so.1
7f84aa0da000-7f84aa27c000 r-xp 00000000 08:03 9136 /usr/lib/libc-2.18.so
7f84aa27c000-7f84aa47b000 ---p 001a2000 08:03 9136 /usr/lib/libc-2.18.so
7f84aa47b000-7f84aa47f000 r--p 001a1000 08:03 9136 /usr/lib/libc-2.18.so
7f84aa47f000-7f84aa481000 rw-p 001a5000 08:03 9136 /usr/lib/libc-2.18.so
7f84aa481000-7f84aa485000 rw-p 00000000 00:00 0
7f84aa485000-7f84aa4a5000 r-xp 00000000 08:03 7209 /usr/lib/ld-2.18.so
7f84aa672000-7f84aa675000 rw-p 00000000 00:00 0
7f84aa6a1000-7f84aa6a4000 rw-p 00000000 00:00 0
7f84aa6a4000-7f84aa6a5000 r--p 0001f000 08:03 7209 /usr/lib/ld-2.18.so
7f84aa6a5000-7f84aa6a6000 rw-p 00020000 08:03 7209 /usr/lib/ld-2.18.so
7f84aa6a6000-7f84aa6a7000 rw-p 00000000 00:00 0
7fff249c8000-7fff249e9000 rw-p 00000000 00:00 0 [stack]
7fff249fe000-7fff24a00000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
zsh: abort (core dumped) ./ppbase < tests/filter
我应该如何正确使用此代码中的自由函数?我可以安全地将任何List转换为:db_type_void-&gt; next(第二个例子中的第5行)?
答案 0 :(得分:2)
free_list(last, t->cols[i]/*type of column*/);
last = last->next;
似乎不正确。 free_list
释放下一行中访问的last
。
编辑:
关于
我可以安全地将任何列表转换为:db_type_void-&gt; next
不干净。 C标准仅保证结构的第一个成员位于偏移0
。因此,将->next
投射到已键入的struct List_db_string *
即可。但是不能保证struct List_db_string *
和struct List_db_void *
具有相同的内部表示,以便
struct List_db_void *next;
next = last->next; /* was last = last->next in question */
可能会导致问题(理论上讲;它可能会在每个相关平台上做正确的事情)。
更简洁的方法是将last->next
转换为正确的类型并访问其next
属性。
注意:所有这些对于访问next
都有效;其他成员(prev
,v
)的行为在未提及演员的情况下未定义。
编辑:
在类似
的泛型类型上实现操作struct list_head {
struct list_head *next;
struct list_head *prev;
}
允许例如。
struct List_db_int {
struct list_head head;
int v;
}
struct List_db_string {
string v;
struct list_head head;
}
(注意attributs的不同顺序)。您可以使用container_of模式从head
计算对象。
答案 1 :(得分:1)
此功能:
free_list(struct List_db_void *elm, enum db_type type) {
switch(type) {
case db_type_int:
free((struct List_db_int*) elm);
break;
case db_type_string:
free((struct List_db_string*) elm);
break;
default:
/*Should not reach*/
return ;
break;
}
}
完全相同(考虑到我们从未经过default
分支,正如您的评论所示)
free_list(struct List_db_void *elm, enum db_type type) {
free(elm);
}
指针强制转换适用于类型系统,并且具有 no 动态语义。编译后它们会消失,可以这么说。
据说我正在看看导致段错误的原因。
编辑:可能是这个!
for (j = 0; j < HOW_MANY_ELEMENTS_REMOVE; j++) {
free_list(last, t->cols[i]/*type of column*/);
last = last->next;
}
释放后你正在使用last
。做点什么
for (j = 0; j < HOW_MANY_ELEMENTS_REMOVE; j++) {
struct List_db_void *temp = last->next;
free_list(last, t->cols[i]/*type of column*/);
last = temp;
}
答案 2 :(得分:1)
一个问题是以下一对行
free_list(last, t->cols[i]/*type of column*/);
last = last->next;
此代码释放last
的内存,然后立即在下一行使用释放的内存。 next
指针的缓存应该在释放last
之前完成。
我不确定这是否会导致你的段错误,但它绝对应该改变。我怀疑这个错误最有可能出现在分配函数中。你可以发帖吗?