views:

72

answers:

3

I have written this function to delete the last node of a singly linked list.

The problem is, it is able to delete all the nodes except the first/starting node.

What is missing from this code snippet?

Please answer my particular problem.

    #include <stdio.h>
#include <stdlib.h>

struct Node
{
    char CharContent;
    struct Node * NextNodePointer;
};
typedef struct Node Node;

#pragma region Prototypes
Node * CreateNewNode(char ch);
Node * AddNode(Node * start, Node * newNode);
void DeleteTailNode(Node * start);
void PrintAllNodes(const Node * start);
#pragma endregion Comments

main()
{
    Node * start = NULL;
    Node * newNode = NULL;

    start = AddNode(start, CreateNewNode('A'));
    start = AddNode(start, CreateNewNode('B'));
    start = AddNode(start, CreateNewNode('C'));
    start = AddNode(start, CreateNewNode('D'));
    PrintAllNodes(start);

    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);

    getch();
}

#pragma region Node * CreateNewNode(char ch)
Node * CreateNewNode(char ch)
{
    struct Node * newNode = (struct Node *) malloc(sizeof(struct Node *));

    newNode->CharContent = ch;
    newNode->NextNodePointer = NULL;

    return newNode;
}
#pragma endregion Comment

#pragma region UnifiedAddNode()
Node * AddNode(Node * start, Node * newNode)
{
    Node * copyOfStart = start;

    if(start == NULL)
    {
        return newNode;
    }
    else
    {
        while(copyOfStart->NextNodePointer != NULL)
        {
            copyOfStart = copyOfStart->NextNodePointer;
        }

        copyOfStart->NextNodePointer = newNode;

        return start;
    }
}
#pragma endregion Comment


void DeleteTailNode(Node * start)
{
    Node * prev = NULL;
    Node * current = start;

    while(current->NextNodePointer != NULL)
    {
        prev = current;
        current = current->NextNodePointer;
    }

    free (current);

    if (prev != NULL)
    {
        prev->NextNodePointer = NULL;
    }
}


#pragma region PrintAllNodes()
void PrintAllNodes(const Node * start)
{
    struct Node * tempRoot = start;

    while(tempRoot != NULL)
    {
        printf("%c, ", tempRoot->CharContent);

        tempRoot = tempRoot->NextNodePointer;
    }

    printf("\n");
}
#pragma endregion Comment
+1  A: 

How do you understand if it's deleted or not ? As I see, nothing here is deleted.. it's a 100% sure memory leak.. you're not using free in DeleteTailNode .. you're just making the allocated memory unaccessible..

Edit: call free( current ) after the loop. And there's no need from the check, if current is NULL, it's safe to delete NULL pointer.

Kiril Kirov
You're doing it wrong (in the else-statement): use **free( current )**, NOT **free(current->NextNodePointer)**
Kiril Kirov
@JMSA - OK, Prasoon solution will delete **exactly** one node.. it's the same, I'm suggesting :)
Kiril Kirov
You're adding four "objects" and you're trying to delete 5. Anyway, that's not the problem. You must add else-statement for the **if (prev != NULL)** where to put **start = NULL; **. Otherwise, current stands uninitialized and you're trying to delete something, noone knows what :)
Kiril Kirov
Kiril Kirov
What ? I didn't get it. My point is, that the problem is with deleting the last element. What other case?? You're still deleting one element from the end of the list. But you can't redirect **start** to point to NULL, when you delete it, if you just pass "Node*" to the function. Did you try that ?
Kiril Kirov
+5  A: 

Where's the call to free() ?

Try this : (Passing address of start to DeleteTailNode)

void DeleteTailNode(Node **start)
{
    Node * prev = NULL;
    Node * current = *start;
    while(current!=NULL && current->NextNodePointer != NULL)
    {
           prev = current;
           current = current->NextNodePointer;
    }

    free (current);

    if (prev != NULL)
    {
           prev->NextNodePointer = NULL;
    }
    if (prev == NULL && *start!= NULL)
        *start = NULL;
}

EDIT

Inside CreateNewNode()

struct Node * newNode = (struct Node *) malloc(sizeof(struct Node *));  
                                                                  ^
                                                                  |  

                                                                 Ouch!!

Change it to : struct Node * newNode = (struct Node *) malloc(sizeof(struct Node));

EDIT 2

Test Run HERE

Prasoon Saurav
Sorry man! This is not working either. Did you run it on VC++2008Express yourself?
JMSA
@JMSA: See EDIT2. Its working fine on my MSVC++ Pro.
Prasoon Saurav
Well! you have changed the parameter to double pointer. I was actually trying to avoid it. Is there any way to avoid it?
JMSA
@JMSA : Why were you trying to avoid it? After deleting the last node i.e `A` you have to do `start =NULL` otherwise `PrintAllNodes()` will segfault (start will be a dangling pointer in that case). So you cannot do that without passing the address of `start` to `DeleteTailNode`.
Prasoon Saurav
For the shake of simplicity.
JMSA
@JMSA : "Simplicity" is not always "Simple". You just saw that. `:-)`
Prasoon Saurav
@Prasoon - I told exactly the same and I'm really interested in why JMSA is trying to avoid this
Kiril Kirov
@JMSA : Your `CreateNewNode()` is also flawed. Did you see EDIT 1?
Prasoon Saurav
At least, accepted your answer(: Finally.
Kiril Kirov
@Kiril : `:)` ...
Prasoon Saurav
+1  A: 

You aren't detecting the case where start is NULL, i.e. the list is empty.

Don't you want to free the next node before setting it to NULL?

If the start node is the last node prev will be NULL when the list traversal completes, but when that happens you are deleting the (NULL) start->NextNodePointer, when you want to delete start itself.

Try:

void DeleteTailNode(Node *& start)
{
    Node * prev = NULL;
    Node * current = start;

    if (start == NULL)
        return;

    while(current->NextNodePointer != NULL)
    {
        prev = current;
        current = current->NextNodePointer;
    }

    if(current != NULL)
        free(current);

    if(current == start)
        start = NULL;

    if(prev != NULL)
        prev->NextNodePointer = NULL;
}
gregjor