分段错误和取消引用指针

Segmentation fault and dereferencing pointer

我正在为学校做一个项目,我必须实现一个队列。 我在我的 main.c 文件中写了一些非常简单的测试,看看是否一切正常,但我遇到了两个错误,我不知道如何修复,我可能需要你们的帮助!

第一个错误

我遇到的第一个错误是 Segmentation fault (core dumped)。我知道这与内存访问问题有关,但老实说我不知道​​我做错了什么。有没有简单的方法来调试 c 中的段错误?

第二个错误

顺便说一句,当我取消注释我的 main.c

的第 9 行时
printf("One node added, size = %d\n",my_queue->size);

我收到另一条错误消息:

main.c: In function ‘main’:
main.c:9:47: error: dereferencing pointer to incomplete type ‘queue_t’ {aka ‘struct queue’}
    9 |  printf("One node added, size = %d\n",my_queue->size);
      |                                               ^~

我发现当您尝试取消引用尚未定义(或声明)的结构时会发生此错误。这条消息让我感到惊讶,因为我确实在我的头文件 queue.h 中声明了我的类型 queue_t 并且我确实在我的 queue.c 文件中定义了它。

你可以在这里找到我所说的所有文件 repo

非常感谢您的帮助,祝您有愉快的一天!

迭戈

编译错误 dereferencing pointer to incomplete type ‘queue_t’ 是由于在 main 中取消引用指向 queue_t 的指针而导致的,这是一个不完整的类型,也就是不透明类型。

queue.h 中的 API 旨在对调用者隐藏结构 queue_t 的定义。调用函数应该只使用指向该结构的指针。所以调用者不应该知道有一个结构字段 size.

解决这个问题的最简单的方法是添加一个 getter 函数到 API 到 return 所请求的值。该函数应在 queue.h 中声明并在 queue.c 中实现,例如

int get_size(queue_t *queue)
{
    int size = -1; /* error return value */
    if(queue != NULL)
    {
        size = queue->size;
    }
    return size;
}

(作为技巧,您可以将结构定义的副本添加到 main.c我不推荐这样做。


为了检查分段错误我用

编译了程序
gcc -Wall -Wextra -pedantic main.c queue.c -o main

运行将程序与valgrind结合为

valgrind ./main

我收到几条错误消息

==25539== Memcheck, a memory error detector
==25539== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25539== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==25539== Command: ./main
==25539== 
First node added had value 42
==25539== Invalid read of size 4
==25539==    at 0x1092FC: dequeue (queue.c:45)
==25539==    by 0x109200: main (main.c:14)
==25539==  Address 0x4a5a0e8 is 8 bytes inside a block of size 16 free'd
==25539==    at 0x483BA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x1093AE: dequeue (queue.c:60)
==25539==    by 0x1091E1: main (main.c:13)
==25539==  Block was alloc'd at
==25539==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x10926D: enqueue (queue.c:25)
==25539==    by 0x1091C4: main (main.c:10)
==25539== 
==25539== Invalid read of size 8
==25539==    at 0x109359: dequeue (queue.c:54)
==25539==    by 0x109200: main (main.c:14)
==25539==  Address 0x4a5a0e0 is 0 bytes inside a block of size 16 free'd
==25539==    at 0x483BA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x1093AE: dequeue (queue.c:60)
==25539==    by 0x1091E1: main (main.c:13)
==25539==  Block was alloc'd at
==25539==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x10926D: enqueue (queue.c:25)
==25539==    by 0x1091C4: main (main.c:10)
==25539== 
==25539== Invalid read of size 8
==25539==    at 0x109382: dequeue (queue.c:57)
==25539==    by 0x109200: main (main.c:14)
==25539==  Address 0x4a5a0e0 is 0 bytes inside a block of size 16 free'd
==25539==    at 0x483BA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x1093AE: dequeue (queue.c:60)
==25539==    by 0x1091E1: main (main.c:13)
==25539==  Block was alloc'd at
==25539==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x10926D: enqueue (queue.c:25)
==25539==    by 0x1091C4: main (main.c:10)
==25539== 
==25539== Invalid free() / delete / delete[] / realloc()
==25539==    at 0x483BA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x1093A2: dequeue (queue.c:59)
==25539==    by 0x109200: main (main.c:14)
==25539==  Address 0x4a5a0e0 is 0 bytes inside a block of size 16 free'd
==25539==    at 0x483BA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x1093AE: dequeue (queue.c:60)
==25539==    by 0x1091E1: main (main.c:13)
==25539==  Block was alloc'd at
==25539==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25539==    by 0x10926D: enqueue (queue.c:25)
==25539==    by 0x1091C4: main (main.c:10)
==25539== 
Second node added had value 43
==25539== 
==25539== HEAP SUMMARY:
==25539==     in use at exit: 16 bytes in 1 blocks
==25539==   total heap usage: 5 allocs, 5 frees, 1,088 bytes allocated
==25539== 
==25539== LEAK SUMMARY:
==25539==    definitely lost: 16 bytes in 1 blocks
==25539==    indirectly lost: 0 bytes in 0 blocks
==25539==      possibly lost: 0 bytes in 0 blocks
==25539==    still reachable: 0 bytes in 0 blocks
==25539==         suppressed: 0 bytes in 0 blocks
==25539== Rerun with --leak-check=full to see details of leaked memory
==25539== 
==25539== For lists of detected and suppressed errors, rerun with: -s
==25539== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)

显然您已经 free 在第 60 行 dequeue 的函数 dequeue 中创建了一个节点

            free(cur);

并且您在第 45 行访问此节点

        int tbr = q->tail->value; //value to be returned

和第 54 行

                cur = cur->next;

和第 57 行

            cur->next = old->next;

然后在第 59 行你再次尝试free这个块

            free(old);

通过在 enqueuedequeue 的条目和 return 添加调试 printfs,我发现第一次调用 dequeue 没有t 在 else 分支中导致错误和 returns。 错误发生在对 dequeue 的第二次调用中,它也在 else 分支中 returns。 显然,在第一次调用 dequeue 时,您 free 将使用一个节点,而在第二次调用中 freed。

我没有详细分析你的程序,但我猜测freedequeueoldcur都是错误的。

运行 你的程序使用调试器一步一步地思考你的列表的节点是如何连接的以及你什么时候必须 free 哪个节点。