Sorted doubly linked list gives bus error when accessing in reverse
I've got a generic doubly-linked list implementation, and was working on insertion. After insertion, I try to iterate backwards through the list starting at the foot, and I get a bus error. To test the code and try to isolate the error I've sprinkled print statements in (not the best debugging procedure but useful for to tell me at a glance what my code is doing). To try and see where the problem arises, after every insertion I ask for the value of the second-last element in the list. I always insert elements in the order 5, 2, 10, 80, 4, 1, 7, 8, and after inserting 4 into the list, it consistently chokes. Full code of the program follows.
dlist_t *
insert_in_order (dlist_t *list, void *value, size_t size,
int (*cmp_fptr)(const void *, const void *))
{
dlnode_t * prev = NULL;
dlnode_t * current = list->head;
dlnode_t * newnode = safe_malloc(sizeof(dlnode_t));
newnode->data = value;
newnode->next = NULL;
newnode->prev = NULL;
printf("Beginning list loop for %d.\n", *(int *) newnode->data);
while (current != NULL && cmp_fptr(newnode->data, current->data) != -1)
{
prev = current;
current = current->next;
}
printf("Insertion point found.\n");
newnode->next = current;
newnode->prev = prev;
if (prev == NULL)
{
printf("Setting for new head\n");
list->head = newnode;
}
else
{
printf("Setting previous next to new node\n");
prev->next = newnode;
}
if (current == NULL)
{
printf("setting for new foot.");
list->foot = newnode;
}
else
{
printf("Setting for new current previous\n");
current->prev = newnode;
}
list->list_len++;
list->size = sizeof(list);
printf("Insertion compete for %d\n\n", *(int *) newnode->data);
printf("Data for surrounding:\n");
if(newnode->next !=NULL)
{
printf("Next is %d \n", *(int *) newnode->next->data);
}
if(newnode->prev != NULL)
{
printf("Prev is %d \n\n", *(int *) newnode->prev->data);
}
if(list->foot->prev != NULL)
{
printf("Gonna print secondlast!\n");
printf("secondlast is%d \n\n", *(int *)list->foot->prev->data);
}
return list;
}
The list definitions are very basic, just
struct dlnode
{
void *data; /* A pointer to a generic satellite data payload */
dlnode_t *next; /* A pointer to the next item in the list *开发者_C百科/
dlnode_t *prev; /* A pointer to the previous item in the list */
};
typedef struct
{
dlnode_t *head; /* A pointer to the head node of the list */
dlnode_t *foot; /* A pointer to the foot node of the list */
int list_len; /* Total number of items in the list */
int size; /* Size of the list in bytes */
} dlist_t;
You can change the function definition however you want, and safe_malloc is just a shortcut method for malloc that you can replace if you're testing the code yourself. cmp_fptr is a function pointer to a simple 'is a greater than b' method.
EDIT: UPDATE The line
printf("secondlast is%d \n\n", *(int *)list->foot->prev->data);
is what causes the program to halt, I've used a debugger. When inserting items to the list, it halts on that line after several insertions. The following is my test harness code that I'm using right now.
int *
alloc_data (int val)
{
int *rv = safe_malloc (sizeof (int));
*rv = val;
return (rv);
}
int
main (void)
{
dlist_t *list = NULL;
int *num = NULL, *rv = NULL;
dlnode_t *tnode = NULL;
list = make_empty_list ();
list = insert_in_order (list, alloc_data (5), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (2), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (10), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (80), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (4), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (1), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (7), sizeof(int), cmp_int);
list = insert_in_order (list, alloc_data (8), sizeof(int), cmp_int);
return(EXIT_SUCCESS);
}
There's a little more to it but that's all I'm testing for now.
Thanks for the list->size tip, I'm not quite sure what I was thinking with it originally.
edit2: thanks for the safe_malloc errorfinding, I thought that was the cause of the problem but I still get the same error. The debugger gives me a sigsegv (segmentation fault) after 4 is inserted and it gets to the line where for sanity I ask for list->foot->prev->data (see above).
Final edit: problem solved by properly mallocing enough space for node data. Thanks to those that helped. There are other issues in my code, but that's best suited to another question, and regarding a different code snippet.
A few things:
As it was already said, the list->size = sizeof(list);
probably doesn't do what you think
The size_t size
passed as argument is probably your main issue and seems dangerous (what is this variable value when you call the function?)
Doing dlnode_t * newnode = safe_malloc(size);
with a wrong size can explain your issue
dlnode_t * newnode = safe_malloc(size);
should probably be replaced by
dlnode_t * newnode = safe_malloc(sizeof(dlnode_t));
Last, in your list, you're using directly void *value
and not a copy of it.
So if you're not calling this function always in the same block, you will have issues
With the same function signature, i think the size parameter should represent the size of the value parameter to make a malloc / memset of it and save it in your list
精彩评论