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
}