C - 链表 valgrind 未初始化错误取决于添加元素的顺序

有袋动物

我一直在研究一个可以接受多种数据类型的 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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章