为什么将相同的地址发送到函数中?
Why are same addresses sent into function?
我正在研究双向链表,我遇到了这个问题。我将逐步粘贴部分代码,我会尝试解释发生了什么。
所以我定义了数据类型:
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");
}
}
所以基本上出错的地方是只保存了一个数据。我在这里使用字符串,但数据的参数和变量是 void*。所以当我输入添加两个节点时,只保存最后输入的数据。同样在 main 中,每次除了第一个 p
都会被 search
函数找到,即使它不存在。正如我所说,调试器说 cmp_str
接收到两个相同地址的参数,这可能是找到错误位置的提示。
答案很简单。人们在学习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/calloc 的结果。如果编译器给你错误,这表明你使用 C++ 编译器编译 C 代码,这不是一个好主意。
您正在为每个添加操作设置相同的数据指针。看来您分配了一次并且每个周期都使用相同的内存。如果我说错了请指正。
您需要分配新的内存并将数据指针的内容深拷贝到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;
...
我正在研究双向链表,我遇到了这个问题。我将逐步粘贴部分代码,我会尝试解释发生了什么。
所以我定义了数据类型:
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");
}
}
所以基本上出错的地方是只保存了一个数据。我在这里使用字符串,但数据的参数和变量是 void*。所以当我输入添加两个节点时,只保存最后输入的数据。同样在 main 中,每次除了第一个 p
都会被 search
函数找到,即使它不存在。正如我所说,调试器说 cmp_str
接收到两个相同地址的参数,这可能是找到错误位置的提示。
答案很简单。人们在学习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/calloc 的结果。如果编译器给你错误,这表明你使用 C++ 编译器编译 C 代码,这不是一个好主意。
您正在为每个添加操作设置相同的数据指针。看来您分配了一次并且每个周期都使用相同的内存。如果我说错了请指正。
您需要分配新的内存并将数据指针的内容深拷贝到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;
...