Reputation: 499
I made a linked list, and a function that returns the iterator. When assigning the iterator to another pointer and freeing the pointer, it does nothing since it's not a reference. How can I delete the item in the list?
Example:
//initialize struct list, insert 1 struct (this is only done if list is empty)
some_struct* struct_list;
struct_list = (some_struct*)malloc(sizeof(some_struct));
strncpy(struct_list->name, "foo", 4);
struct_list->name[3] = '\0';
typedef struct some_struct
{
char name[MAXLENGTH];
struct some_struct* next;
} some_struct;
some_struct* find_struct(char* name)
{
char* iter;
for (iter = struct_list; iter != NULL; iter = iter->next)
{
if (strcmp(name, iter->name) == 0)
return iter;
}
return NULL;
}
some_struct* name;
name = find_struct("foo"); //since there's only 1 struct, name == struct_list
free(name); //struct_list still contains 1 struct with name "foo"
I made sure the linked list works as it should, it does find the name but this doesn't do anything
Edit: For clarification, unlinking/linking does get rid of the struct. But if there's only 1 item in the struct, this doesn't work
Upvotes: 0
Views: 92
Reputation: 181179
I made a linked list, and a function that returns the iterator. When assigning the iterator to another pointer and freeing the pointer, it does nothing since it's not a reference. How can I delete the item in the list?
Whether it is a reference has nothing to do with anything. You can indeed free the memory of the list node via any pointer to it, but I have no idea why you think that would automatically remove it from the list, even if it were a reference. Instead, the node's predecessor ends up with an invalid next
pointer, and dereferencing that produces undefined behavior. That UB could plausibly take a form similar to the behavior it would have exhibited prior to the memory being freed, at least for a time.
You seem to have it backward. If you want to remove a node from the list then that is your primary objective; freeing the node's memory is secondary, and then only appropriate if you are in fact finished with the node. Deleting from a singly-linked list requires finding the predecessor of the node to delete, then updating its next
pointer appropriately. Depending on exactly how you set things up, deleting the first element may be a special case.
You having clarified in comments that the issue is with deleting the only element from a one-element list (or, I'd wager, the first element no matter how long the list is), it seems appropriate to expand on the special case that I referred to.
Evidently you have a global variable
some_struct *struct_list;
that points to the first list node when there is one, and which is null when the list is empty. Given a pointer to a node you want to delete, such as one returned by your find_struc()
function, to delete that from your list you'll need a function along these lines:
void delete_struct(some_struct *to_delete) {
if (struct_list == to_delete) {
// special case: deleting the first element
// ... do something here ...
} else {
some_struct *pred = struct_list;
while (pred && pred->next != to_delete) {
pred = pred->next;
}
if (pred) {
assert(pred->next == to_delete);
pred->next = pred->next->next;
free(to_delete);
}
}
}
Evidently, then, the problem is what should be the "do something here". But I don't see what the mystery or problem would be. You know what's supposed to happen, and you seem capable of making it happen:
struct_list = struct_list->next;
free(to_delete);
Obviously (or maybe not so much), the variable you have to set NULL is the one that the rest of your code looks to for the list head.
If you want to remove the special-caseness of deleting the first element, then consider using a dummy head node, which need not even be dynamically allocated. Then the first data-bearing element has a genuine (but non-data-bearing) predecessor, and you don't need a special case. There is at least one other alternative, but you're having enough trouble with pointers already that I'll leave that one for some other time.
Upvotes: 3