-1

Can anyone help me where I'm going wrong please !!!, I'm a beginner to programming, I'm new to DSA, I'm not able to find my mistake, here is the code please go through it:

This is the outline of my question, hope it is clear! :)


sample input : 3 16 13 7 1 2
3 is the number of elements to input into a linked list
so 16 13 7 are elements of the linked list initially
1 is the element I'm interested to insert
2 is the position where I want to insert the element 1
so the expected output will be:
sample output: 16 13 1 7

The problem I'm facing :


The output I'm getting is: 13 1 7
So the problem is not every element in the list is getting returned, please help !!!

This is the code I tried, any suggestions are encouraged, :)

   struct SinglyLinkedListNode 
  {
        int data;
        SinglyLinkedListNode* next;
  };

    SinglyLinkedListNode* insertNodeAtPosition(SinglyLinkedListNode* head, int data, int position) 
{
    int i = 0;
    SinglyLinkedListNode *pcurr, *pnew;

    pnew = (SinglyLinkedListNode*)malloc(sizeof(SinglyLinkedListNode));
    if(position == 0)
    {
        pnew->data = data;
        pnew->next = head->next;
        head = pnew;
        return head;
    }
    if(head == NULL)
    {
        pnew ->data = data;
        return pnew;
    }
    else
    {
        do 
        {
            pcurr = head;
            pcurr = pcurr->next;
            head = head->next;
            i++;
        }
        while (i != position-1);
        pnew->next = pcurr->next;
        pnew->data = data;
        pcurr->next = pnew;
        return head;
    }
}

I would be glad if anyone suggests a good visualising platform for viewing our code line by line especially for c , just like in python.

mystic
  • 13
  • 1
  • 6
  • 1
    What is SinglyLinkedListNode? – Vlad from Moscow May 28 '20 at 11:33
  • "visualising platform" how about your ide? Or do you mean a debugger? (c)GDB then. Also how are we supposed to help you if you don't provide us with what's going wrong and what is expected – Tarick Welling May 28 '20 at 11:38
  • @VladfromMoscow, it should be Struct SinglyLinkedListNode, it is basically the normal way we initialize a node – mystic May 28 '20 at 11:53
  • @TarickWelling I have given the sample input/output and the output I have got too, please go through my question. – mystic May 28 '20 at 11:55
  • 1
    @mystic It is an invalid construction. There is nothing normal. – Vlad from Moscow May 28 '20 at 11:58
  • @VladfromMoscow Ya, thank you, but that doesn't fix my error, please go through my code completely – mystic May 28 '20 at 12:03
  • As for which IDE to use for C, I'd probably go for Eclipse because there is a pre-packaged version with the C dev tools. My second choice might be VS Code. But really, almost all IDEs out there support C to some degree. – Hulk May 28 '20 at 12:13
  • @Hulk thanks, but I meant something similar to pythontutor.com, – mystic May 28 '20 at 12:23
  • @TarickWelling hope the question is clear now?, let me know so that I can improve,I'm new to StackOverflow as well. – mystic May 28 '20 at 12:29
  • `SinglyLinkedListNode* insertNodeAtPosition(...) {...}` SinglyLinkedListNode is not a type name. Are you using a C++ compiler? – wildplasser May 28 '20 at 13:18
  • @wildplasser SinglyLinkedListNode* insertNodeAtPosition(...) {...}, is a pointer to the function of type SinglyLinkedListNode, this is written in " C " language, hope it clears the confusion. – mystic May 28 '20 at 13:26
  • BTW: why do you allocate two nodes when you intend to insert only one? – wildplasser May 28 '20 at 14:17
  • @mystic well, it seems that site also supports C: http://www.pythontutor.com/c.html#mode=edit – Hulk May 28 '20 at 14:43
  • @wildplasser, ya, but that doesn't solve the error, I would be glad if you help me out with mistake in that code. – mystic May 28 '20 at 16:09
  • Maybe there is more than one error? – wildplasser May 28 '20 at 16:14
  • @wildplasser I would like to know what the second error is! – mystic May 28 '20 at 16:30

2 Answers2

1

There were a few issues and the code is actually much simpler.

You were doing malloc twice instead of only once, so you were leaking memory on each call.

Don't cast malloc:. See: Do I cast the result of malloc?

SinglyLinkedListNode is a bit long. When used in a lot of places, this doesn't scale well. How about something shorter like Node or SlNode


Here's a refactored version:

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

typedef struct node Node;
struct node {
    int data;
    Node *next;
};

Node *
insertNodeAtPosition(Node *head, int data, int position)
{
    int i = 0;
    Node *prev;
    Node *pcurr;
    Node *pnew;

    pnew = malloc(sizeof(Node));
    pnew->data = data;

    // find the correct place to insert
    prev = NULL;
    for (pcurr = head;  pcurr != NULL;  pcurr = pcurr->next, i += 1) {
        if (i >= position)
            break;
        prev = pcurr;
    }

    // link up the element that will follow the new node
    pnew->next = pcurr;

    // insert into middle or end of list
    if (prev != NULL)
        prev->next = pnew;

    // insert into empty list or _before_ the first node
    else
        head = pnew;

    return head;
}

void
printlist(Node *head)
{
    Node *pcurr;

    printf("List:");

    for (pcurr = head;  pcurr != NULL;  pcurr = pcurr->next)
        printf(" %d",pcurr->data);

    printf("\n");
}

int
main(void)
{
    FILE *fi;
    Node *head = NULL;
    int count;
    int newval;
    int pos;

    fi = fopen("input.txt","r");
    if (fi == NULL) {
        perror("input.txt");
        exit(1);
    }

    fscanf(fi," %d",&count);

    for (int i = 0;  i < count;  ++i) {
        fscanf(fi," %d",&newval);
        printf("new: %d\n",newval);
        head = insertNodeAtPosition(head,newval,count + 10);
    }
    printlist(head);

    while (1) {
        if (fscanf(fi," %d %d",&newval,&pos) != 2)
            break;
        printf("insert: %d at %d\n",newval,pos);
        head = insertNodeAtPosition(head,newval,pos);
    }
    printlist(head);

    fclose(fi);

    return 0;
}

Here's the test file: input.txt:

3
16 13 7
1 2
9 0
8 0

Here is the program output:

new: 16
new: 13
new: 7
List: 16 13 7
insert: 1 at 2
insert: 9 at 0
insert: 8 at 0
List: 8 9 16 13 1 7

UPDATE:

can you also tell me why we have to use a pointer *prev? why only pcurr and pnew are not sufficient? It would help me in learning this new concept being a beginner.

Sure. If we're inserting at the head of the list because the list is empty or we want to insert at the head (i.e. we want a new head even if we have other nodes in the list), we adjust head.

But, if we're inserting in the middle of the list or appending to the end of the list, we need to know what the previous node is.

Consider that we're trying to append to the end of the list. We need to know the existing/prior tail [last element] of the list. If we have:

head | node1 | node2 | node3

Then, node3 is the tail of the list. node3->next will be NULL. To append, we create the new node (pnew) and we have to set node3->next = pnew, so we get:

head | node1 | node2 | node3 | pnew
                       prev

Here, prev will end up having the value of node3, so setting prev->next = pnew is just like setting node3->next = pnew. Note that when appending to the end, pcurr will be NULL.

We call it prev because it (the previous node) can also be any node that we wish to insert after, even if prev is in the middle of the list (e.g. node2). That would look like (before the insertion):

head | node1 | node2 | node3
               prev    pcurr

After the insertion, we want:

head | node1 | node2 | pnew | node3
               prev           pcurr

In this case, pcurr will be node3 (i.e. prev->next).

So, prev points to the node just prior to where we want to insert pnew and pcurr points to the node just after where we want to insert pnew.

In other words, after insertion, prev is the node just to the left of pnew (i.e. the node that precedes it). pcurr is the node just to the right of pnew (i.e. the node that follows it). If pcurr is null, there is no following node, but setting pnew->next = pcurr works in all cases, regardless of the values of head or prev being null or not.

If prev ends up being NULL, this means that the list is either empty or we wish to insert pnew at the head/front of the list. In that case, we can't try to dereference [a null] prev, so we just set head to pnew. Then, we're returning an updated head pointer.

There are several possible list states and insertion operations:

  1. list is empty (adjust the head)
  2. we want to insert the new node before the head of the [non-empty] list (adjust the head)
  3. we want to insert the new node somewhere in the middle of the list
  4. we want to append the new node at the end of the list (adjust tail or head if tail is null)

I think it would be helpful for you to diagram each of these separate cases using pencil and paper. Then, verify, by hand, that the code handles each of these cases, even if the list has prior elements or is empty.

The important thing to note about the above code is that it uses variables that work for several different cases, using the same code path, minimizing the number of if/else clauses to handle the various edge cases in a uniform way.

The type of simplification I did occurs again and again when coding. Thoroughly understanding what was done and why will help you immeasurably in the future.

Any one function that one writes, by itself, may not seem like much. But, magnify this across hundreds or thousands of functions, and it will pay dividends far beyond the initial extra work.

A maxim: As simple as it needs to be--and no simpler

The simpler (i.e. the cleaner) the code, the more likely it is to be correct, complete, and the easier it is to check for correctness. Contrary to popular belief, I've also found that the simpler code also tends to be faster.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • I got it, kudos to you! :) – mystic May 28 '20 at 16:20
  • can you also tell me why we have to use a pointer *prev? why only pcurr and pnew are not sufficient? It would help me in learning this new concept being a beginner. – mystic May 28 '20 at 16:27
  • BTW, don't forget to upvote/accept the answer. See: https://stackoverflow.com/help/someone-answers – Craig Estey May 28 '20 at 19:21
  • sure I will do that, also I have upvoted it, probably it's not showing because I'm a new user, It pops up a message: Thanks for the feedback! Votes cast by those with less than 15 reputation are recorded, but do not change the publicly displayed post score, so I have accepted your answer. – mystic May 29 '20 at 03:05
0
 struct SinglyLinkedListNode 
  {
        int data;
        SinglyLinkedListNode* next;
  };

    SinglyLinkedListNode* insertNodeAtPosition(SinglyLinkedListNode* head, int data, int position) 
{
    int i = 0;
    SinglyLinkedListNode *temp1, *pcurr, *prev;
    temp1 = (SinglyLinkedListNode *)malloc(sizeof(SinglyLinkedListNode));
    prev = (SinglyLinkedListNode*)malloc(sizeof(SinglyLinkedListNode));
    if(position == 0&&head!=NULL)
    {
        temp1->data = data;
        temp1->next = head;     //new node's next will point to head and new node will become the new head
        head = temp1;          //since the insertion is made at start, new node(temp1) will becomes the new head.
        return head;
    }
    else if(head == NULL)      //if linked list is empty
    {
        temp1->data = data;    
        temp1->next = NULL;
        head = temp1;         //just set the new node as head of linked list and return the head node
        return head; 
    }
    else
    {
        int i=0;         //for iterating to the required position
        temp->data = data;

        //store 2 nodes, one node which will store prev node and another to store current node. The temp node will go between these 
        prev = head,pcurr = head->next; 
        while(i != position-1 && pcurr != NULL){  //traverse the linked list till you reached the insertion position
            i++;
            prev = pcurr;
            pcurr = pcurr->next;
        }
        if(i != position-1){
            return head;     //can't insert at the specified position
        }
        prev->next = temp;   //point the node preceding the insertion position to new node to be inserted
        temp->next = pcurr; //point the new node to the next node to maintain the linked list
        return head;
    }  
}

I hope the above changes will solve your question. I have added comments wherever required to help you understand the code. Please comment if you find any error and I will correct it.

Abhishek Bhagate
  • 5,583
  • 3
  • 15
  • 32
  • thank you so much, Your code has solved my problem, I would be glad if you let me know why I can't use a do-while loop, would be more helpful if you can tell my error in my code.Thanks again ;) – mystic May 28 '20 at 12:53
  • do-while would work as well with minor edits in my answer code. – Abhishek Bhagate May 28 '20 at 13:02