C 区分堆栈内存和堆内存
假设我有一个列表实现,它使用以下C 区分堆栈内存和堆内存,c,free,calloc,C,Free,Calloc,假设我有一个列表实现,它使用以下listnode\t: typedef struct ListNode { struct ListNode *next; struct ListNode *prev; void *value; } listnode_t; 如您所见,这是一个双链接列表。我还有一个list\u t,它有两个指针指向listnode\u t作为列表的第一个和最后一个节点以及大小。 现在我的主要目标是: int main(int argc, char *argv
listnode\t
:
typedef struct ListNode {
struct ListNode *next;
struct ListNode *prev;
void *value;
} listnode_t;
如您所见,这是一个双链接列表。我还有一个list\u t
,它有两个指针指向listnode\u t
作为列表的第一个和最后一个节点以及大小。
现在我的主要目标是:
int main(int argc, char *argv[]){
...
// Create two empty lists
list_t *list1 = make_list();
list_t *list2 = make_list();
// Populate one with ints
int x = 4;
int y = 5;
list_push(list1, &x);
list_push(list1, &y);
// Populate other with strings
string_t *str1 = make_string("foo");
string_t *str2 = make_string("bar");
list_push(list2, str1);
list_push(list2, str2);
...
// Delete at the end
destroy_list(list1);
destroy_list(list2);
}
我在实现destroy\u list
时遇到问题。这就是我所尝试的
void destroy_list(list_t *list)
{
listnode_t *cur = list -> first;
for(cur = list -> first; cur != NULL; cur = cur -> next){
if(cur -> prev){
free(cur -> prev);
}
}
free(list -> last);
free(list);
list = NULL;
}
我的问题是,我试图在listnode\t
中使用void*
,以便能够通用地使用此列表。但是当我删除东西时,应用free(cur->prev)
似乎有问题。当我像上面一样使用int这样的东西的列表时,因为它们是在堆栈上分配的,所以我想一切都很顺利。但如果我有如上所述的字符串列表,由于我在字符串实现中使用动态分配,我必须首先应用free(cur->prev->value)
。我不知道如何才能做到这一点,因为如果我添加它,那么我会遇到另一个问题,即试图释放主服务器上堆栈分配的内存
我该怎么办,我不明白这种通用列表行为
// Populate one with ints
int x, y = 4, 5;
list_push(list1, &x);
list_push(list1, &y);
不要这样做
您为列表
结构建立的界面有效地表示,当调用列表(push)
时,指针的“所有权”将传递到列表,并且指针将被列表中的释放()。将指针传递给堆栈变量违反了该接口——如果要传入整数,则需要为列表创建一个副本以获得所有权
列表
结构的另一个接口可能是将指针和长度传递到列表_push
,并让该函数复制该结构,而不是保留它。这是否合适将取决于您对该结构所考虑的用例
(另外,intx,y=4,5
并没有做你认为它能做的事。你可能是指intx=4,y=5
)
不要这样做
您为列表
结构建立的界面有效地表示,当调用列表(push)
时,指针的“所有权”将传递到列表,并且指针将被列表中的释放()。将指针传递给堆栈变量违反了该接口——如果要传入整数,则需要为列表创建一个副本以获得所有权
列表
结构的另一个接口可能是将指针和长度传递到列表_push
,并让该函数复制该结构,而不是保留它。这是否合适将取决于您对该结构所考虑的用例
(另外,intx,y=4,5
并没有做你认为它能做的事。你可能是指intx=4,y=5
)
int x,y=4,5
我不认为这是你认为的那样
但是当我删除东西时,应用cur->prev
似乎有问题
“有问题”不是一个技术术语。准确描述你期望发生的事情,并准确描述发生了什么
当我像上面一样使用int这样的东西的列表时,因为它们是在堆栈上分配的,所以我想一切都很顺利
不,它们一点也不好。当您在堆栈上获取一个变量的地址时,您将自己设置得非常失望,因为一旦您的函数返回,堆栈就是垃圾
但如果我有如上所述的字符串列表,由于我在字符串实现中使用动态分配,我必须首先应用cur->prev->value
你说的“申请”是什么意思?你说的“第一”是什么意思
我不知道该怎么做因为如果我加上它
“添加”是什么意思?什么是“它”?加在什么上面?在科技文本中,我们从不使用像“it”和“that”这样的介词。把它说清楚
然后,我遇到了另一个问题,即试图释放主机上堆栈分配的内存
同样,“问题”并不能说明什么。在任何情况下,如果我想猜猜你的问题是什么,解决方法很简单:总是为值
分配空间,这样你就可以随时释放它
这不是从双链接列表中删除节点的方式。要从双链接列表中删除节点Y,必须首先取消节点Y的链接,以便节点Z的prev
指向节点X,节点X的next
指向节点Z,然后可以释放节点Y(释放其值后)当然,您必须始终记住,节点Y可能是列表中的第一个或最后一个节点,在这种情况下,它没有上一个或下一个节点,相反,您必须修改列表结构本身的头部或尾部
int x,y=4,5
我不认为这是你认为的那样
但是当我删除东西时,应用cur->prev
似乎有问题
“有问题”不是一个技术术语。准确描述你期望发生的事情,并准确描述发生了什么
当我像上面一样使用int这样的东西的列表时,因为它们是在堆栈上分配的,所以我想一切都很顺利
不,它们一点也不好。当您在堆栈上获取一个变量的地址时,您将自己设置得非常失望,因为一旦您的函数返回,堆栈就是垃圾
但如果我有如上所述的字符串列表,由于我在字符串实现中使用动态分配,我必须首先应用cur->prev->value
你说的“申请”是什么意思?你说的“第一”是什么意思
我不知道该怎么做因为如果我加上它
“添加”是什么意思?什么是“它”?加在什么上面?在科技文本中,我们从不使用像“it”和“that”这样的介词。把它说清楚
那我就有另一个问题了
if(cur -> prev){
free(cur -> prev);
}
struct LISTROOT {
listnode_t list;
void (*freeitem)(void * value);
};
struct LISTROOT myList;
struct MYTYPE {
char *buffer;
int *whatever;
};
void myFreeItem(struct MYTYPE *item)
{
if (item) {
if (item->buffer) free(item->buffer);
...
free(item);
}
}
myList.list= make_list(myFreeItem);
if(cur -> prev){
if (myList.freeitem) mylist.freeitem(cur->value);
free(cur -> prev);
list_t *list1 = make_list(0); // dont free items
list_t *list1 = make_list(1); // free items
typedef struct ListNode {
struct ListNode *next;
struct ListNode *prev;
char value[];
} listnode_t;
void list_push(list_t *t, void *value, size_t valueSize) {
listnode_t *newNode = malloc(sizeof(listnode_t) + valueSize);
memcpy (newNode->value, value, valueSize);
// ... any code necessary for attaching the new node to the list goes here
}