我正在处理双链表,遇到了这个问题。我会一步一步地粘贴代码的一部分,我试图解释发生了什么。
所以我定义了数据类型:
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;
}
作为add
和search
函数自变量的比较函数为:
int cmp_str(const void *a, const void *b){
return strcmp((const char*)a, (const char*)b);
}
调用search
和add
的主函数的一部分:
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");
}
}
所以基本上错误的地方是只保存了一个数据。这里我使用字符串,但数据的参数和变量是空的。因此,当我输入add两个节点时,只保存最后键入的数据。此外,一般情况下,除了第一个p
之外,每次都由search
函数找到,即使它不存在。正如我所说的,调试器说cmp_str
接收到两个地址相同的参数,这可能是找到错误所在的提示
您正在为每个添加操作设置相同的数据指针。似乎您分配了一次,并且每个周期都使用相同的内存。如果我错了,请纠正我。
您需要分配新的内存并将数据指针的内容深度复制到新的->数据
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;
...
答案很简单。当人们学习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);
// ...
补充说明:
- 在
sizeof
中使用对象而非类型 - 不要强制转换malloc/caloc的结果。如果编译器给你错误,这表明你使用C++编译器编译C代码,这不是一个好主意