【问题标题】:Why are same addresses sent into function? [duplicate]为什么将相同的地址发送到函数中? [复制]
【发布时间】:2021-05-09 16:20:22
【问题描述】:

我正在研究双向链表,但遇到了问题。我将逐步粘贴部分代码,并尝试解释发生了什么。

所以我已经定义了数据类型:

typedef struct node {
    void *data;
    struct node *prev, *next;
} NODE;

add 函数的这一部分可能有问题。我检查了所有场景,但我不想粘贴不必要的代码。

void add(NODE **phead, NODE **ptail, void *data, int (*cmp)(const void*, const void*)){
    NODE *p, *q, *new = (NODE*)calloc(1, sizeof(NODE));
    new->data = data;
    if(*phead == 0)
        *phead = *ptail = new;

    else if((*cmp)((*phead)->data, data) > 0){
        new->next = *phead;
        (*phead)->prev = new;
        *phead = new;
    }

当我调试代码时,我看到当函数指针被调用时,相同的地址被作为参数发送。

NODE *search(NODE *head, NODE *tail, const void *data, int (*cmp)(const void*, const void*)){
    if(head == 0)
        return 0;
    while ((*cmp)(head->data, data) < 0 && (*cmp)(tail->data, data) > 0)
    {
        head = head->next;
        tail = tail->prev;
    }
    if((*cmp)(head->data, data) == 0)
        return head;
    else if((*cmp)(tail->data, data) == 0)
        return tail;
    else 
        return 0;
}

比较函数addsearch的参数是:

int cmp_str(const void *a, const void *b){
    return strcmp((const char*)a, (const char*)b);
}

调用searchadd 的主函数的一部分:

int main(){
    NODE *head = 0, *tail = 0;
    char c, *data = (char*)calloc(20, sizeof(char));
    do
    {
        printf("Add [A], delete [D], write [W], search [S], end [0]: ");
        scanf("\n%c", &c);
        if(c == 'A'){
            get_string(&data);
            NODE *p = search(head, tail, data, &cmp_str);
            if(p){
                p->data = data;
                printf("Data updated!\n");
            }
            else{
                add(&head, &tail, data, &cmp_str);
                printf("Data added.\n");
            }
        }

所以基本上出错的地方是只保存了一个数据。在这里,我使用字符串,但数据的参数和变量是 void*。所以当我输入添加两个节点时,只保存最后输入的数据。同样在 main 中,除了第一个 p 之外,每次都由 search 函数找到,即使它不存在。正如我所说,调试器说cmp_str 接收到相同地址的两个参数,这可能暗示要找到错误所在。

【问题讨论】:

    标签: c linked-list void


    【解决方案1】:

    您将每个添加操作的数据指针设置为相同。似乎您分配了一次并为每个周期使用相同的内存。如果我错了,请纠正我。

    你需要分配新的内存并将数据指针的内容深拷贝到new->data中。

    void add(NODE **phead, NODE **ptail, void *data, int (*cmp)(const void*, const void*)){
        NODE *p, *q, *new = (NODE*)calloc(1, sizeof(NODE));
        new->data = data;
        ...
    

    【讨论】:

      【解决方案2】:

      答案很简单。人们在学习 C 时存在相当普遍的误解。

      data 指针始终指向同一个内存位置。

      add 函数中,您只需将此引用分配给所有节点。在C中=不复制指针所引用的内存只分配引用。

      您需要在每次交互时分配它(在main 中)或将其复制到add 函数中。

      void add(NODE **phead, NODE **ptail, void *data, size_t data_size, int (*cmp)(const void*, const void*)){
          NODE *p, *q, *new = calloc(1, sizeof(*new));
          //check if calloc did not return NULL
          new -> data = calloc(1, data_size);
          //check if calloc did not return NULL
          memcpy(new->data, data, data_size);
          // ...
      

      一些补充说明:

      1. 使用对象而不是sizeof 中的类型。
      2. 不要转换 malloc/calloc 的结果。如果编译器出现错误,则表明您使用 C++ 编译器编译 C 代码,这不是一个好主意。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-05
        • 2011-08-24
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        • 2016-12-18
        • 2019-07-10
        相关资源
        最近更新 更多