Still able to access a struct that has been freed

2019-09-21 09:05发布

问题:

This question already has an answer here:

  • Why freed struct in C still has data? 7 answers

So, I have a struct:

tyepdef struct node {
    struct node *next;
    double value;
} NodeT, *NodeTP;

and I have three functions:

int deleteNode(NodeTP p)
{
    free(p);
    p = NULL;

    return 1;
}

int deleteOne(NodeTP list)
{
    if (list->next != NULL)
        deleteOne(list->next);
    else 
        deleteNode(list);

    return 1;
}

int print(NodeT list)                                                           
{                                                                               
    printf("%lf\n", list.value);                                                

    if (list.next != NULL)                                                      
        print(*list.next);                                                      

    return 1;                                                                   
}   

deleteOne will hand the final node in the list to deleteNode so that the memory can be freed. When a node is initialized, no memory is allocated for next, until it is needed. instead, it is initially set to be NULL. This is why I don't free(p->next).

So, if I have a list of nodes (let's say their values are 3.5, 2.5, 1.2, 3.6) the print function will print the following:

3.5
2.5
1.2
3.6

Then, if the final node is deleted, and I print again, the following is printed:

3.5
2.5
1.2
3.6

If I delete another node, I get an error because I'm trying to free memory that has already been freed.

It seems as though print is accessing a memory location still, that has already been freed. However, it seems like it shouldn't be trying to read this if the 'next' node is equal to NULL. I realize this is undefined behaviour, but how can I fix this?

回答1:

When the tail node of a linked list is deleted, it is the programmer's responsibility to set the previous' node's next element to NULL.

When the tail node is free()ed, the memory that the node occupied will continue to hold the values it was assigned (when it was a node) until that memory is used for another purpose. Hence, it is not a good idea to continue to reference that memory after freeing it.

Sometimes, I write my own free() function to ensure that the pointer passed to free is no longer capable of accessing the memory. Something like this:

void myFree(void **ptr)
   {
   free(*ptr);
   *ptr=NULL;
   }

Then, when the tail node is freed, the parent node's next pointer is automatically set to NULL:

void myFreeTailNode(NodeT **head)
   {
   NodeT *parentNode   = NULL;

   if(NULL == head)
      return;

   if(NULL == *head)
      return;

   if(NULL == (*head)->next)
      myFree((void **)head);
   else
      {
      for(parentNode = *head; parentNode->next->next; parentNode=parentNode->next)
          /*Do Nothing */ ;

      MyFree((void **)&parentNode->next);
      }
   }


回答2:

You should do this if you want NULL assigned outside the function:

int deleteNode(NodeTP * p)
{
    free(*p);
    *p = NULL;

    return 1;
}

And change your calls to deleteNode.



标签: c struct free c99