I'm working on a project for school and I have to implement a queue. I wrote some very simple tests in my main.c file to see if everything worked fine, but I get two errors I don't know how to fix, and I might need a little help from you guys !
The first error I get is a Segmentation fault (core dumped)
. I know it has to do with a memory access problem, but honestly I don't know what I did wrong. Is there a simple way to debug segfaults in c ?
By the way, when I uncomment line 9 of my main.c
printf("One node added, size = %d\n",my_queue->size);
I get another error message:
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);
| ^~
I found out that this error occurs when you try to dereference a struct that hasn't been defined (or declared) yet. This message surprises me because I did declare my type queue_t in my header file queue.h and I did define it in my queue.c file.
You can find all the files i'm talking about on this repo
Thanks a lot for your help and have a good day !
Diego
The compilation error dereferencing pointer to incomplete type ‘queue_t’
results from dereferencing a pointer to queue_t
in main
which is an incomplete type AKA opaque type.
The API in queue.h
is designed to hide the definition of the structure queue_t
from the caller. The calling functions are supposed to use a pointer to this structure only. So the caller is not supposed to know that there is a structure field size
.
The clean way to solve this would be to add a getter function to the API to return the requested value. The function should be declared in queue.h
and implemented in queue.c
, e.g.
int get_size(queue_t *queue)
{
int size = -1; /* error return value */
if(queue != NULL)
{
size = queue->size;
}
return size;
}
(As a hack you could add a copy of the structure definition to main.c
. I don't recommend this.)
To check the segmentation fault I compiled the program with
gcc -Wall -Wextra -pedantic main.c queue.c -o main
Running the program with valgrind
as
valgrind ./main
I get several error messages
==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)
Apparently you have already free
d a node in function dequeue
at line 60
free(cur);
and you access this node at line 45
int tbr = q->tail->value; //value to be returned
and line 54
cur = cur->next;
and line 57
cur->next = old->next;
Then at line 59 you try to free
this block again
free(old);
By adding debug printf
s at the entry and return of enqueue
and dequeue
I found out that the first call to dequeue
doesn't result in an error and returns in the else
branch.
The errors occur in the second call to dequeue
which also returns in the else
branch.
Apparently in the first call to dequeue
you free
a node that will be used and free
d in the second call.
I didn't analyze your program in detail, but I guess that it is wrong to free
both old
and cur
in dequeue
.
Run your program step by step using a debugger and think about how the nodes of your list are connected and when you have to free
which node.