1

First of all, apologies if this is a duplicate question. I'm just learning C++ and probably don't know the correct search terms to find what I'm sure has already been asked.

Anyways, I'm teaching myself C++ by working through the 30 days of code on HackerRank. However, I've hit a roadblock that I can't seem to solve when asked to implement an insert method for a LinkedList. Conceptually, I know what needs to be done, but syntactically I'm running into an issue.

Below is my code, with debugging printouts included. What seems to be happening is that new_node keeps getting put in the same location in memory, regardless of which loop iteration its on. How do I ensure this gets a new place in memory? I seem to get the same behavior regardless of if I declare new_node as static or not.

Here's the code:

#include <iostream>
#include <cstddef>
using namespace std;    
class Node
{
    public:
        int data;
        Node *next;
        Node(int d){
            data=d;
            next=NULL;
        }
};
class Solution{
    public:
    /// ----- MY CODE BEGINS HERE:
      Node* insert(Node *head,int data)
      {
          cout << "----------" << endl;
          cout << data << endl;
          int i = 0;

          if (head){
              Node *curr = head;
              Node *next = curr->next;

              while(next){
                  cout << data << "," << i << ": " << curr << "," << curr->next 
                   << "," << curr->data << endl;
                  i++;
                  curr = curr->next;
                  next = curr->next;
              }
              cout << data << "," << i << ": " << curr << "," << curr->next 
                   << "," << curr->data << endl;
              static Node new_node = Node(data);
              curr->next = &new_node;
              cout << " ***  Adding " << data << " at " << curr->next
                   << " and next points to: " << (curr->next)->next << endl;
              return head;
          }
          else{
              static Node new_head = Node(data);
              cout << " ***  Adding " << data << " at " << &new_head
                   << " and next points to: " << new_head.next << endl;
              return &new_head;
          }
      }
      // ------- MY CODE ENDS HERE
      void display(Node *head)
      {
          Node *start=head;
          while(start)
          {
              cout<<start->data<<" ";
              start=start->next;
          }
      }
};
int main()
{
    Node* head=NULL;
    Solution mylist;
    int T,data;
    cin>>T;
    while(T-->0){
        cin>>data;
        head=mylist.insert(head,data);
    }   
    mylist.display(head);

}

When I run this with the sample input of (4, 2, 3, 4, 1), I get the following:

----------
2
 ***  Adding 2 at 0x6022e0 and next points to: 0
----------
3
3,0: 0x6022e0,0,2
 ***  Adding 3 at 0x7fff3ddc1d80 and next points to: 0
----------
4
4,0: 0x6022e0,0x7fff3ddc1d80,2
4,1: 0x7fff3ddc1d80,0,3
 ***  Adding 4 at 0x7fff3ddc1d80 and next points to: 0x7fff3ddc1d80
----------
1
1,0: 0x6022e0,0x7fff3ddc1d80,2
1,1: 0x7fff3ddc1d80,0x7fff3ddc1d80,4
1,2: 0x7fff3ddc1d80,0x7fff3ddc1d80,4
1,3: 0x7fff3ddc1d80,0x7fff3ddc1d80,4
1,4: 0x7fff3ddc1d80,0x7fff3ddc1d80,4
1,5: 0x7fff3ddc1d80,0x7fff3ddc1d80,4

and this continues until a Segmentation Fault ebcause its caught in an infinite loop...

Any ideas why new_node keeps getting placed in the same memory location (with or without the static)? Is this not even the main issue and I'm completely missing the point? Thanks in advance!

-- C++ neophyte.


EDIT: The suggested duplicate doesn't quite address the question here. My trouble was not understanding the difference between pointers and references, but rather the difference between:

Node node_1 = Node(data);
static node_2 = Node(data);
node_3 = new Node(data);

As I was unaware of the new operator at the time of writing the question (obviously!), I did not know to (a) search for this or (b) include this term in the title. The title has been edited for clarity, and this edit has been included for future readers.

Community
  • 1
  • 1
brettb
  • 771
  • 1
  • 6
  • 14
  • 1
    Linked List is one of the nasties dropped on people learning programming languages to force them to learn pointers. The key things here are ownership of the pointer (who is responsible for maintaining and releasing the memory pointed at when no longer needed) and the lifespan of the memory pointed at (when is it deleted). With respect to the linked list and getting the list to work, nothing beats drawing the connections and changes to the connections required on a piece of paper and then using the drawing to establish the operations that need to be performed. – user4581301 Jul 19 '16 at 21:52
  • *Uh huh ...* **:-D** And I *heartily* agree with you that your first tool, when working-out algorithms like these, must be "a legal pad and a number-two *pencil."* ### The implementation as-written seems to me to be a little bit too baroque: you really don't need *both* a `curr` *and* a `next` pointer. You just need to iterate until you discover that `curr->next == NULL`. At that point, you allocate a new node (whose `next` pointer is `NULL`), and assign it to `curr->next`. As your "legal pad and number-two pencil" will show. – Mike Robinson Jul 19 '16 at 23:04
  • @MikeRobinson Thanks for the feedback -- but neither of you are really addressing my question (as the accepted answer did), which was not really anything about the algorithm, but about the syntax and particulars of C++... – brettb Jul 20 '16 at 00:16
  • Feel free to "accept" any answer that best suits ye. With my blessings. – Mike Robinson Jul 20 '16 at 01:46

2 Answers2

5

When you declare a variable static, there's only one copy of that variable. It gets created the first time you execute the declaration, and future calls to the function reuse the same data. So every time you use new_node, it's the same node.

You need to allocate dynamic data with the new operator. As the operator name implies, this creates a new object every time you use it. When you add a remove() operation to the class, it will use delete to free the memory.

  Node* insert(Node *head,int data)
  {
      cout << "----------" << endl;
      cout << data << endl;
      int i = 0;

      if (head){
          Node *curr = head;
          Node *next = curr->next;

          while(next){
              cout << data << "," << i << ": " << curr << "," << curr->next 
               << "," << curr->data << endl;
              i++;
              curr = curr->next;
              next = curr->next;
          }
          cout << data << "," << i << ": " << curr << "," << curr->next 
               << "," << curr->data << endl;
          Node *new_node = new Node(data);
          curr->next = new_node;
          cout << " ***  Adding " << data << " at " << curr->next
               << " and next points to: " << (curr->next)->next << endl;
          return head;
      }
      else{
          Node *new_head = new Node(data);
          cout << " ***  Adding " << data << " at " << &new_head
               << " and next points to: " << new_head->next << endl;
          return new_head;
      }
  }
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

you use a static variables. These are created only once, and are the same for every function call! your intend is to create a new Node always, so these variables are not static!

try it out with

Node* new_head = new Node(data);
return new_head;
// as well as
Node* new_node = new Node(data);
curr->next = new_node;

All nodes must be create on the free store (with new), otherwise they get cleaned up when the function ends. This means you are always referencing to not existing variables, which is a memory corruption. You must as well provide a destructor to delete the new'd nodes. For more information read about the lifespan of variables.

Further notes:

  • use nullptr
  • std::list, or std::linked_list are the containers for lists (i know, you want to learn, but take a look at them)
  • your class is all public -> you can use a struct, since its the same, but default public for access specifiers.
  • use unique_ptr for the ownership (this is kinda advanced, but use it early)
jonas_toth
  • 872
  • 5
  • 8
  • And in my opinion there is **no** clearly-justifiable need to specify *anything* `static` in such an algorithm! Since there is no such reason, IMHO the variable should not be declared `static` at all. – Mike Robinson Jul 19 '16 at 23:07
  • agreeing. static variables should be used very sparely anyway. Usually stackvariables to everything u need (even dynamic memory management using containers and so on). Even the need for free store variables is seldom there. Assuming that smartpointers qualify as stack variables as well – jonas_toth Jul 19 '16 at 23:48
  • Thanks @jonas_toth -- this answer was also helpful! – brettb Jul 20 '16 at 00:23
  • Really? Oh dear, you really *are* a beginner! – Mike Robinson Jul 20 '16 at 01:47