0

The question is to remove duplicates from sorted list and the code is :

 /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* deleteDuplicates(ListNode* head) {
            if (head == NULL) return NULL;
            for (ListNode* prev = head, *cur = head->next; cur; cur = cur->next)
            {
                if (prev->val == cur->val)
                {
                    prev->next = cur ->next;
                    delete cur;
                }
                else
                {
                    prev = cur;
                }
            }
            return head;
        }
    };

The code is right ,My puzzle is :

the pointer "cur" , after "delete" , use" cur" and" cur = cur->next" in "for". Why is it OK?

Sorry to trouble, The leetcode give AC to the code , so I doubt myself, Thanks to the answers.

Fanl
  • 1,451
  • 2
  • 10
  • 13

5 Answers5

3

A clarification first: a pointer is something that points to a memory area.

If you call delete on a pointer you're going to free whatever that pointer pointed to, but you will not destroy the pointer itself. You can reuse that pointer, but dereferencing it again after it has been deleted it's undefined behavior since nothing guarantees the memory it used to point to will still be available to you.

Your code causes UB since after

delete cur;

you dereference that pointer with cur = cur->next. You have no guarantees that cur still points to a valid memory area where next has an actual meaning as an address.

A correct version of your code would be the following:

ListNode* deleteDuplicates(ListNode* head) {
  if (head == NULL) return NULL;
  for (ListNode* prev = head, *cur = head->next; prev->next; cur = prev->next)
  {
    if (prev->val == cur->val)
    {
      prev->next = cur->next;
      delete cur;
    }
    else
    {
      prev = cur;
    }
  }
  return head;
}

Live Example

Marco A.
  • 41,192
  • 25
  • 117
  • 233
1

No, it's not OK. It's just undefined behaviour, anything is possible. In this case, the content the pointer point to happens not be cleared only, but you can't and shouldn't rely on it.

songyuanyao
  • 147,421
  • 15
  • 261
  • 354
0

The function has undefined behaviour. You may not access an object after its deletion.

So this loop

        for (ListNode* prev = head, *cur = head->next; cur; cur = cur->next)
        {
            if (prev->val == cur->val)
            {
                prev->next = cur ->next;
                delete cur;
            }
        //...

is wrong.

The function can be defined the following way

ListNode* deleteDuplicates( ListNode *head ) 
{
    if ( head )
    {        
        for ( ListNode *current = head; current->next; )
        {
            if ( current->val == current->next->val )
            {
                ListNode *tmp = current->next;
                current->next = current->next->next;
                delete tmp;
            }
            else
            {
                current = current->next;
            }            
        }
    }        

    return head;
}
Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
0

A deleted pointer could point anywhere. It is an undefined behaviour. It is a good practice to point the pointer NULL after deletion. It will explicitly make sure that you won't misuse the pointer instead crash with null pointer exception. I would change your code like this:-

            if (curr!=NULL && prev->val == cur->val)
            {
                prev->next = cur ->next;
                delete cur;
                cur = NULL;
            }

EDIT: I just checked that after delete you are accessing next with

cut = cur->next;

In your case it could work as you are executing your code with fixed data and the memory pointed by pointer cur was not overwritten. However in fairly complex program, there is good chance of cur being something else and cur->next could take you anywhere in the universe (in most cases segmentation error if using non flat memory architecture). But it is an unintended state. Thus making it NULL will definitely give you error. Its better to exit with an exception rather than doing something unexpected.

Mangat Rai Modi
  • 4,649
  • 5
  • 37
  • 67
  • Not everybody agrees it is wise to set a pointer to NULL after deletion. See [here](http://stackoverflow.com/a/12194183/33499) and [here](http://stackoverflow.com/a/12196704/33499). And remember even if this could work in this simple situation; What if you use a version of `delete` which clears all memory? Some compilers do such things if you switch to debug mode. – wimh Aug 15 '15 at 09:32
  • @Wimmel I read the links and found that there are programmers supporting both the practices as you could see http://stackoverflow.com/questions/704466/why-doesnt-delete-set-the-pointer-to-null. Basically if your code is clean enough then no worries, but if you are not sure about accessing your dangling pointer then I believe its better to get an null pointer exception. Imagine an OS like VxWorks with no memory protection. With a dangling pointer one could overwrite OS memory area also. – Mangat Rai Modi Aug 15 '15 at 10:08
0

The code is definitely NOT OK. The code is broken. Doing cur = cur->next after deleting the object pointed by cur is undefined behavior.

AnT
  • 291,388
  • 39
  • 487
  • 734