C - 链表valgrind未初始化错误取决于添加的顺序元素
C - linked list valgrind uninitialized error depending on order elements are added
我一直在研究可以接受多种数据类型的 C 通用链表。在测试我的链表搜索功能时,我注意到一个奇怪的 valgrind 未初始化错误,我无法弄清楚。出于某种原因,如果我通过先附加一个整数,然后附加一个双精度数来初始化链表,然后搜索任何双精度数(是否存在于 LL 中),我会收到以下错误:
==64398== Conditional jump or move depends on uninitialised value(s)
==64398== at 0x1099C0: ll_contains (gll.c:301)
==64398== by 0x1092E8: contains_tests (gll_tests.c:17)
==64398== by 0x10934C: main (gll_tests.c:24)
==64398==
==64398== HEAP SUMMARY:
==64398== in use at exit: 0 bytes in 0 blocks
==64398== total heap usage: 6 allocs, 6 frees, 1,124 bytes allocated
==64398==
==64398== All heap blocks were freed -- no leaks are possible
==64398==
==64398== For lists of detected and suppressed errors, rerun with: -s
==64398== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
但是,如果我先加双精度,然后加整数,然后搜索,一切都很好。以下是错误的产生方式(第 4 行和第 5 行的顺序):
struct LL* test_ll = ll_init();
int int_val = 69;
double double_val = 69.69;
ll_add_end(test_ll, &int_val, INT); /* This order causes the error! */
ll_add_end(test_ll, &double_val, DOUBLE);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
struct LL* test_ll = ll_init();
int int_val = 69;
double double_val = 69.69;
ll_add_end(test_ll, &double_val, DOUBLE); /* This order causes no errors! */
ll_add_end(test_ll, &int_val, INT);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
相关函数如下:
节点是这样创建的:
struct Node* _create_node(void* data, enum ListType type)
{
int data_size;
struct Node* to_add = (struct Node*)malloc(sizeof(struct Node));
to_add->type = type;
to_add->next = NULL;
to_add->prev = NULL;
/* allocate memory for node's data */
switch (type)
{
case INT:
to_add->data = malloc(sizeof(int));
data_size = sizeof(int);
break;
case DOUBLE:
to_add->data = malloc(sizeof(double));
data_size = sizeof(double);
break;
case CHAR:
to_add->data = malloc(sizeof(char));
data_size = sizeof(char);
break;
case STRING:
data_size = strlen((const char*)data) + 1;
to_add->data = malloc(sizeof(char) * data_size);
break;
default:
return false;
}
/* copy data by byte into newly allocated memory */
int i;
for (i = 0; i < data_size; i++)
{
*(char*)(to_add->data + i) = *(char*)(data + i);
}
return to_add;
}
这是将节点附加到链表的方式:
bool ll_add_end(struct LL* list, void* data, enum ListType type)
{
struct Node* to_add = _create_node(data, type);
to_add->prev = list->tail;
if (list->tail)
{
list->tail->next = to_add;
}
list->tail = to_add;
list->head = (list->count == 0) ? to_add : list->head;
list->count++;
return true;
}
这是错误的包含函数。错误总是发生在指示的行:
bool ll_contains(struct LL* list, void* data, enum ListType type)
{
struct Node* current = list->head;
switch (type)
{
case INT:
while (current != NULL)
{
if (*((int*)current->data) == *((int*)data))
{
return true;
}
current = current->next;
}
break;
case DOUBLE:
while (current != NULL)
{
if (*((double*)current->data) == *((double*)data)) /* ERROR HERE */
{
return true;
}
current = current->next;
}
break;
case CHAR:
while (current != NULL)
{
if (*((char*)current->data) == *((char*)data))
{
return true;
}
current = current->next;
}
break;
case STRING:
while (current != NULL)
{
if (strcmp((char*)current->data, (char*)data) == 0)
{
return true;
}
current = current->next;
}
break;
default:
return false;
}
return false;
}
经过测试,我确定错误是由于尝试访问current->data引起的,但仅在DOUBLE的情况下,然后,仅当首先将整数添加到链表时。我尝试在 create_node 函数中使用 calloc 而不是 malloc,但错误仍然存在。很长一段时间以来,我一直无法找出导致这种行为的原因,因此我决定寻求帮助。提前致谢。
问题是您有一个混合类型列表,但 ll_contains
强制比较一种固定类型。
所以当你按照这个顺序执行时,发生的事情是
ll_add_end(test_ll, &double_val, DOUBLE); /* This order causes no errors! */
ll_add_end(test_ll, &int_val, INT);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
double
值在列表中排在第一位,因此它 returns 在与 int
比较之前。
顺序颠倒时
ll_add_end(test_ll, &int_val, INT); /* This order causes the error! */
ll_add_end(test_ll, &double_val, DOUBLE);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
您首先拥有 int
,然后是 double
。所以你强制比较 int
和 double
if (*((double*)current->data) == *((double*)data)) /* ERROR HERE */
但 current->data
实际上是指向 int
的指针。当你 malloced
它时,你可能得到的不仅仅是 4 个字节 - iirc 它将是 24 个字节。因此,当您在第 4 个未初始化之后执行此比较字节时。
在你的比较函数中,你需要在转换和检查之前检查类型
数据。
while (current != NULL)
{
if (current->type) == type)
switch (type)
{
case INT:
if (*((int*)current->data) == *((int*)data))
{
return true;
}
break;
// etc.
}
current = current->next;
}
我一直在研究可以接受多种数据类型的 C 通用链表。在测试我的链表搜索功能时,我注意到一个奇怪的 valgrind 未初始化错误,我无法弄清楚。出于某种原因,如果我通过先附加一个整数,然后附加一个双精度数来初始化链表,然后搜索任何双精度数(是否存在于 LL 中),我会收到以下错误:
==64398== Conditional jump or move depends on uninitialised value(s) ==64398== at 0x1099C0: ll_contains (gll.c:301) ==64398== by 0x1092E8: contains_tests (gll_tests.c:17) ==64398== by 0x10934C: main (gll_tests.c:24) ==64398== ==64398== HEAP SUMMARY: ==64398== in use at exit: 0 bytes in 0 blocks ==64398== total heap usage: 6 allocs, 6 frees, 1,124 bytes allocated ==64398== ==64398== All heap blocks were freed -- no leaks are possible ==64398== ==64398== For lists of detected and suppressed errors, rerun with: -s ==64398== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
但是,如果我先加双精度,然后加整数,然后搜索,一切都很好。以下是错误的产生方式(第 4 行和第 5 行的顺序):
struct LL* test_ll = ll_init();
int int_val = 69;
double double_val = 69.69;
ll_add_end(test_ll, &int_val, INT); /* This order causes the error! */
ll_add_end(test_ll, &double_val, DOUBLE);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
struct LL* test_ll = ll_init();
int int_val = 69;
double double_val = 69.69;
ll_add_end(test_ll, &double_val, DOUBLE); /* This order causes no errors! */
ll_add_end(test_ll, &int_val, INT);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
相关函数如下:
节点是这样创建的:
struct Node* _create_node(void* data, enum ListType type)
{
int data_size;
struct Node* to_add = (struct Node*)malloc(sizeof(struct Node));
to_add->type = type;
to_add->next = NULL;
to_add->prev = NULL;
/* allocate memory for node's data */
switch (type)
{
case INT:
to_add->data = malloc(sizeof(int));
data_size = sizeof(int);
break;
case DOUBLE:
to_add->data = malloc(sizeof(double));
data_size = sizeof(double);
break;
case CHAR:
to_add->data = malloc(sizeof(char));
data_size = sizeof(char);
break;
case STRING:
data_size = strlen((const char*)data) + 1;
to_add->data = malloc(sizeof(char) * data_size);
break;
default:
return false;
}
/* copy data by byte into newly allocated memory */
int i;
for (i = 0; i < data_size; i++)
{
*(char*)(to_add->data + i) = *(char*)(data + i);
}
return to_add;
}
这是将节点附加到链表的方式:
bool ll_add_end(struct LL* list, void* data, enum ListType type)
{
struct Node* to_add = _create_node(data, type);
to_add->prev = list->tail;
if (list->tail)
{
list->tail->next = to_add;
}
list->tail = to_add;
list->head = (list->count == 0) ? to_add : list->head;
list->count++;
return true;
}
这是错误的包含函数。错误总是发生在指示的行:
bool ll_contains(struct LL* list, void* data, enum ListType type)
{
struct Node* current = list->head;
switch (type)
{
case INT:
while (current != NULL)
{
if (*((int*)current->data) == *((int*)data))
{
return true;
}
current = current->next;
}
break;
case DOUBLE:
while (current != NULL)
{
if (*((double*)current->data) == *((double*)data)) /* ERROR HERE */
{
return true;
}
current = current->next;
}
break;
case CHAR:
while (current != NULL)
{
if (*((char*)current->data) == *((char*)data))
{
return true;
}
current = current->next;
}
break;
case STRING:
while (current != NULL)
{
if (strcmp((char*)current->data, (char*)data) == 0)
{
return true;
}
current = current->next;
}
break;
default:
return false;
}
return false;
}
经过测试,我确定错误是由于尝试访问current->data引起的,但仅在DOUBLE的情况下,然后,仅当首先将整数添加到链表时。我尝试在 create_node 函数中使用 calloc 而不是 malloc,但错误仍然存在。很长一段时间以来,我一直无法找出导致这种行为的原因,因此我决定寻求帮助。提前致谢。
问题是您有一个混合类型列表,但 ll_contains
强制比较一种固定类型。
所以当你按照这个顺序执行时,发生的事情是
ll_add_end(test_ll, &double_val, DOUBLE); /* This order causes no errors! */
ll_add_end(test_ll, &int_val, INT);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
double
值在列表中排在第一位,因此它 returns 在与 int
比较之前。
顺序颠倒时
ll_add_end(test_ll, &int_val, INT); /* This order causes the error! */
ll_add_end(test_ll, &double_val, DOUBLE);
assert(ll_contains(test_ll, &double_val, DOUBLE) == true);
您首先拥有 int
,然后是 double
。所以你强制比较 int
和 double
if (*((double*)current->data) == *((double*)data)) /* ERROR HERE */
但 current->data
实际上是指向 int
的指针。当你 malloced
它时,你可能得到的不仅仅是 4 个字节 - iirc 它将是 24 个字节。因此,当您在第 4 个未初始化之后执行此比较字节时。
在你的比较函数中,你需要在转换和检查之前检查类型 数据。
while (current != NULL)
{
if (current->type) == type)
switch (type)
{
case INT:
if (*((int*)current->data) == *((int*)data))
{
return true;
}
break;
// etc.
}
current = current->next;
}