我一直在研究一个可以接受多种数据类型的 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
值是列表中的第一个值,因此它在与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
。所以你强制比较 anint
和 adouble
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;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句