-2
#include<stdio.h>

struct node {
    int info;
    struct node *next;
};

typedef struct node *nodeptr;
nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;

nodeptr getnode(void)
{
    nodeptr p;
    p = (nodeptr) malloc(sizeof(struct node));
    return p;
}

void freenode(nodeptr p)
{
    free(p);
}


int main()
{
    int i;
    nodeptr *k;
    int a;
    int *px;
    int r;
    nodeptr end;
    nodeptr s;
    nodeptr start;

    p = getnode();
    q = getnode();
    q = start;
    p = end;

    for (i = 0; i < 6; i++) {
        printf("enter value");
        scanf("%d", &r);
        p = getnode();
        p->info = r;

        q->next = p;

        q = q->next;

    }

    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

    scanf("%d", &a);
    end = getnode();
    end->info = a;
    end->next = NULL;

    for (q = start; q->next != NULL; q = q->next)
        ;

    q->next = end;
    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

    for (q = start; q->next->next != NULL; q = q->next)
        ;

    freenode(q->next);
    q->next = NULL;
    q = start;

    while (q->next != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }


    return 0;
}

in this program alist is made and an element is inserted at the end in this the element is getting deleted but the list is not shown properly only last two elements are getting displayed please help so as to show the whole list with element deleted

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • could you give more info (the output) – dzada Sep 02 '13 at 18:16
  • 9
    Have you checked out any of the *dozens* of questions and their answers on this site from looking for "[c] delete node in linked list", [such as this one](http://stackoverflow.com/questions/2848289/deleting-a-node-from-linked-list-in-c) ? – WhozCraig Sep 02 '13 at 18:19
  • What is your input and expected output? –  Sep 02 '13 at 18:56

2 Answers2

4

There is a lot wrong, undortunately. As WhozCraig said, there's a lot of other posts on this topic, so you should have probably searched a little more before posting. But since you have, let's walk through some of the issues together.

nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;

Here you are declaring a ton of global variables, most with bad names. What's i? What's p? What's q? Further down, you redeclare variables with the same names. Some with the same type, others with different type. This make it confusing to know which variable you're referencing.

Generally speaking, avoid global variables and choose descriptive names. In this case, you can just get rid of i, p and q.

Also, you never initialize plist to anything; you should get into the habit of initializing variables to some sane default value. In this case, NULL could be appropriate, but since you do not use the variable at all it can be deleted.

nodeptr getnode(void)
{
    nodeptr p;
    p = (nodeptr) malloc(sizeof(struct node));
    return p;
}

This is good, however in C you should not cast the result of malloc to a particular type as this is considered bad form and can cause subtle and hard to detect bugs. Just assign the return from malloc directly.

Secondly, you never check to make sure that malloc succeeded. Granted, it's unlikely that it would fail in your simple program, but you should get in the habit of checking the return value of functions that can fail.

And you should probably initialize the allocated memory to some default value, because the memory returned to you by malloc is full of junk. In this case, something like this seems appropriate:

if(p) /* only if we allocated memory. */
    memset(p, 0, sizeof(struct node));

There are times when you could skip this, but clearing the memory is a sane default practice.

void freenode(nodeptr p)
{
    free(p);
}

This is also fine, but you should consider verifying that p is not NULL before you call free. Again, this comes down to robustness, and it's a good habit to get into.

int main()
{
    int i;
    nodeptr *k;
    int a;
    int *px;
    int r;
    nodeptr end;
    nodeptr s;
    nodeptr start;

Again, here we have a lot of unitialized variables, but at least some of the names are a bit better. But notice what happens:

You declare a variable called i of type int. But you've already declared a global variable called i that is of type nodeptr. So now, the variable in the local scope (the int) shadows (that is, it hides it) the global variable. So inside main the name i refers to the int. This just adds to the confusion when someone is reading your program.

    p = getnode();
    q = getnode();

OK... so, over here you allocate two new nodes and make p and q point to those nodes. So far so good.

    q = start;
    p = end;

Oops... now this is a problem. We now make p and q point to wherever start and end respectively point to.

And where do those point to? Who knows. Both start and end are unitialized, so they can point to anything. From this point on, your program exhibits undefined behavior: this means that anything can happen. Most likely, in this case, it will just crash.

Unfortunately from here on down, things become a lot more confusing. Instead of trying to explain everything, I'll just give some general commentary.

    for (i = 0; i < 6; i++) {
        printf("enter value");
        scanf("%d", &r);
        p = getnode();
        p->info = r;

        q->next = p;

        q = q->next;    
    }

This loop is supposed to read 6 integers and put them in our linked list. This seems like a simple thing to do but there are issues.

First of all, you never check the return of scanf to know if the input operation succeeded. As I said before, you should always check the return value of functions that can fail and handle the failure accordingly. But in this case, let's ignore that rule.

A big problem is that q points to a random location in memory. So we're in undefined behavior land.

Another big problem is that there are two cases to consider: when the list is empty (i.e. the first time we're adding a number to the list when i == 0) and when the list is not empty (i.e. every other time). The behavior in those two cases differs. When i == 0 we can't just blindly set q->next, because even if q didn't point to a random location, there would, conceptually, be no q the way it's used here.

What we need here is some extra logic: if this is the first node that we are creating, set q to point to that node. Otherwise, set q->next to that node and then do q = q->next.

Please note, also, that you never set p->next anywhere, which would cause your list to not be NULL-terminated (something that you rely on here and in other loops). The memset fix in getnode corrects this problem, but generally you should make sure that if your code expects a particular behavior ("an unlinked node's next pointer points to NULL; lists are NULL-terminated") you should have code to ensure that behavior.

    q = start;

Again, here, we reset q to point to start which is still uninitialized and points to garbage.

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

This is a classic printing loop. Nothing wrong here, per se, although I think that stylistically, those parentheses around q->next are overkill and make reading the code a little more difficult than it has to be. My guideline would be to only add parentheses when they're necessary to override the default evaluation order of C or when the parentheses helps to visually explain to the reader how to group the expression in his head when mentally parsing the code.

    scanf("%d", &a);
    end = getnode();
    end->info = a;
    end->next = NULL;

This is fine, except for the error-checking issue with scanf, although you don't prompt the user to enter a number. But you correctly and explicitly make end->next point to NULL which is great.

    for (q = start; q->next != NULL; q = q->next)
        ;

Again, the problem here is that q is set to start which, unfortunately, still points to garbage.

    q->next = end;
    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

This is the second time you've had to type this code to print the list. Generally, you should avoid code duplication. If you find that you need a particular code block in more than one place, it makes sense to split it out into a function and use the function. This makes understanding and maintaining the code easier.

    for (q = start; q->next->next != NULL; q = q->next)
        ;

This loop is tricky to understand because of the q->next->next bit. Ask yourself "if I'm reading this, am I immediately sure that q->next can't ever be NULL?" If you aren't, then you really ought to rewrite this loop.

    freenode(q->next);
    q->next = NULL;
    q = start;

Again, q is made to point to start which is unitialized. But hey, if we haven't crashed yet... ;)

    while (q->next != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

And again... this should really be a function.

    return 0;
}

For a better implementation I refer you to one of the many other questions asked here (just search for "linked list delete". The implementation in this question by Khalid Waseem could also be of help, but it's not very documented, so you will have to carefully study and analyze the code to make sure that you understand it.

Community
  • 1
  • 1
Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
  • What, exactly, does ensuring that you don't pass `NULL` to `free()` have to do with robustness? `free(NULL)` is explicitly defined as a safe no-op. – This isn't my real name Sep 09 '13 at 16:24
  • @ElchononEdelson touché – kinda. It's true that `free(NULL)` is explicitly defined a no-op, *however* calling `free` with a `NULL` pointer is *almost always* indicative of a failure of some kind, whether in the logic or the implementation; at least that has been my experience. – Nik Bougalis Sep 09 '13 at 19:41
  • That needs to be specified, then. The way you mentioned it makes it seem that calling `free(NULL)` is a problem in itself, as opposed to being merely an indicator of a logic error elsewhere in the code. – This isn't my real name Sep 10 '13 at 01:08
0

See below implementation for a better understanding.

struct node {
    int info;
    struct node *next;
};

typedef struct node node;

//Function to print a given single linked list.
void print_list(node *start)
{
    //Check if the given list is empty. 
    if(start == NULL)
            printf("List Empty!!!");
    else
    {
            printf("Current List:");
            //Visit each node one by one 
            while(start != NULL)
            {
                    printf(" %d", start->info);
                    start = start->next;
            }
    }
}
//Function to insert a node at end of single linked list with given data 
node* insert_at_end(node *start, int data)
{
    node *ptr;

    //Create a new node and assign memory using malloc  
    node* new_node = (node*)malloc(sizeof(node));
    if(new_node != NULL)
    {
        //Initialize new node with data.
        new_node->info = data;
        new_node->next = NULL;
    }
    else
    {   //Panic
        printf("\nMemory not allocated. Insertion failed!!!");
        return start;
    }

    //If input list is empty. then new_node becomes the first node of link list.
    if(start == NULL)
            return new_node;
    else
    {
            //travel to the last node of list
            ptr = start;
            while(ptr->next != NULL)
                    ptr = ptr->next;
            //Attach the newly created node at end of list.
            ptr->next = new_node;
            return start;
    }
}

//Delete a node from the end of a Single linked list
node* delete_at_end(node *start)
{
    node *ptr;

    //If input list is empty. nothing to delete just return. 
    if(start == NULL)
            return NULL;
    //Just one node in the given linked list.
    else if(start->next == NULL)
    {
            //Free the memory assigned to the node.
            free(start);
            return NULL;
    }
    else
    {       //Travel to the second last node of the linked list.
            ptr = start;
            while(ptr->next->next != NULL)
                    ptr = ptr->next;
            //free the last node. 
            free(ptr->next);
            ptr->next = NULL;
            return start;
    }
}

int main()
{
    int i, data;
    node *Head_node = NULL;

    for(i = 1; i<=5 ; i++)
    {
            printf("\nEnter node %d :", i);
            scanf("%d", &data);

            // Insert at End
            Head_node = insert_at_end(Head_node, data);

            // Print current List
            print_list(Head_node);
    }

    for(i = 5; i>=1 ; i--)
    {
            printf("\nDeleting node %d :\n", i);

            // Delete at End
            Head_node = delete_at_end(Head_node);

            // Print current List
            print_list(Head_node);
    }

    return 0;
}
  • @Sancho I think a downvote is a little harsh for *working* and *relatively* clean code. @Khalid you should avoid casting the return value of `malloc`. – Nik Bougalis Sep 02 '13 at 20:01
  • @Nik Bougalis malloc return type is void* . Is it not necessary to typecast it to the type of the pointer variable to which it is being assigned? A little explanation will be very helpful. Thanks in advance. – Khalid Waseem Sep 03 '13 at 13:20
  • @KhalidWaseem In C it is not necessary - there's an implicit conversion. For more on why casting should be avoided you can check out [this SO question](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – Nik Bougalis Sep 03 '13 at 19:36