0

Summary Report

Thanks for all the helpful feedback. cin.clear() was very helfpul; so was the remark about setting next to NULL. But the final problem (as diagnosed in the comments) was that I was using Ctrl+D to escape, and cin >> k wasn't handling this correctly. When I added k > 0 into the while condition (see updated code) and escaped with a negative number, it all started working.


I hate to post large amounts of code, but I don't think I can trim this any further. The point is that my program works the first go-around, but not the second. (Skip to main to see what I mean.)

#include <iostream>
using namespace std;

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

void print_list(ListNode* node) {
  cout << node->data << endl;
  while ((node = node->next) != NULL) {
    cout << node->data << endl;
  }
}

ListNode* read_list() {
  ListNode *head, *tail;
  int k;

  head = NULL;
  while ((cin >> k) && k > 0) {
       if (head == NULL) {
          head = tail = new ListNode;
       } else {
          tail->next = new ListNode;
          tail = tail->next;
       }
       tail->data = k;
       tail->next = NULL;
  }
  return head;
}

int main() {
  ListNode *list1, *list2;

  list1 = read_list();
  print_list(list1);    // Works

  list2 = read_list();
  print_list(list2);    // Does not work!

  return 0;
}

And then here is the output:

Press ENTER or type command to continue
1
3
5
7
List1
1
3
5
7
List2

Command terminated

Do you see how it terminates before printing List2? (The first four lines are from stdin. See main.) What is going wrong here? I don't understand why the same logic would work the first time, but not the second.

Perhaps it's because I am not freeing the memory for the first linked list?

ktm5124
  • 11,861
  • 21
  • 74
  • 119
  • 1
    I'm guessing it's cos you don't handle the non int data coming from cin, so the 2nd list never gets populated. – John3136 Mar 12 '13 at 06:11
  • I press Ctrl+D to interrupt the read to stdin. Is this the problem? – ktm5124 Mar 12 '13 at 06:14
  • I think so, but my head is in Java today, so the fine details of cin is not in my head. Dietrich is right too "next" is not set, and will cause you problems. – John3136 Mar 12 '13 at 06:17
  • 1
    Since you never gave any input for List2, then that list is empty. When you call printList, node is null so node->data will cause a segmentation fault. – Matthew T. Staebler Mar 12 '13 at 06:20
  • It turns out that this modest comment is the answer. – ktm5124 Mar 12 '13 at 06:39

4 Answers4

3

There are multiple problems with this code.

  1. You forgot to set next to NULL on the last element. This will cause a crash for any non-empty list.

  2. You need std::cin.clear() before reading from it again. The EOF flag is "sticky".

  3. The print_list() function doesn't handle empty lists. This will crash for any empty list.

Any one of these problems will cause your program to terminate or crash, so you have to fix all of them. Note how one error makes the program crash for empty lists, and a different error causes a crash for non-empty lists -- between the two of them, the program crashes for all lists. Well, if you're lucky, at least. If you're unlucky it might not crash.

Here's a list of tools that would have automatically caught errors #1 and #3:

  • GDB (run gdb ./a.out instead of ./a.out, remember to compile with -g)
  • Mudflap (compile with -fmudflap -lmudflap)
  • Valgrind (run valgrind ./a.out instead of ./a.out)
  • Clang static analyzer

So, you should be using at least one of those four tools. I like to use all four on the same project.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • I wondered about this. I tried it and it didn't solve the problem. But it seems that I should be doing it anyway. – ktm5124 Mar 12 '13 at 06:13
  • @ktm5124: Don't fiddle with things until they work, it's a reckless way of fixing broken programs. The `next` field IS uninitialized, and until you fix that, your program IS BROKEN. – Dietrich Epp Mar 12 '13 at 06:15
  • No, I understand. But I just set next to NULL, and I still get the same output. I will update the code in my post to reflect this - done. – ktm5124 Mar 12 '13 at 06:15
1

You should call cin.clear() after the first read_list() . The reason can be found here.

The following code works well:

#include <iostream>                                                                                                                    
using namespace std;

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

void print_list(ListNode* node) {
  cout << node->data << endl;
  while ((node = node->next) != NULL) {
    cout << node->data << endl;
  }
}

ListNode* read_list() {
  ListNode *head, *tail;
  int k;

  head = NULL;
  while (cin >> k) {
       if (head == NULL) {
          head = tail = new ListNode;
       } else {
          tail->next = new ListNode;
          tail = tail->next;
       }
       tail->data = k;
       tail->next = NULL;
  }
  return head;
}

int main() {
  ListNode *list1, *list2;

  list1 = read_list();
  print_list(list1);
  cin.clear(); // ADD this line 

  list2 = read_list();
  print_list(list2);

  return 0;
}

The problem is caused by the cin in the second read_list() function call. The first read_list(), print_list() works well.

However, according to the debugger, no ListNode is created after return from the read_list(), the list2 is 0x0, that is NULL, which cause the second print_list() segmentation fault.

The reason why the 2nd read_list return NULL is because the while loop does not run. the value of statement cin >> k is false.

Additionally

The above answer is wrong. The problem is still there if simply modifying the read_list function like the following.

ListNode* read_list() {
  ListNode *head, *tail;
  int k;

  head = NULL;
  while (cin >> k) {
       if (head == NULL) {
          head = tail = new ListNode;
       } else {
          tail->next = new ListNode;
          tail = tail->next;
       }
       tail->data = k;
       tail->next = NULL;
  }
  return head;
}
Community
  • 1
  • 1
Kun Ling
  • 2,211
  • 14
  • 22
  • This program will also crash if the list is empty. – Dietrich Epp Mar 12 '13 at 06:32
  • Yes, while I am afraid the author is asking why the program crashes when the list is not empty. – Kun Ling Mar 12 '13 at 06:37
  • `cin.clear()` was very helpful. The other problem was that I was using Ctrl+D to escape from standard input. When I added `&& k > 0` into the while loop condition, I was able to run the program successfully by entering a negative number. – ktm5124 Mar 12 '13 at 06:41
  • You can use cin.ignore() to specify how to escape from the standard input. http://www.cplusplus.com/reference/istream/istream/ignore/?kw=cin.ignore – Kun Ling Mar 12 '13 at 06:45
0
head = NULL;
while (cin >> k) {
   if (head == NULL) {
      head = tail = new ListNode;
   } else {

I hope you see the problem. First you set the head to null and then check whether its null or not.

Try something like this:

ListNode* readList(ListNode* head)
{
    int data;
    cin >> data;

    ListNode* nNode = new ListNode;
    nNode->data = data;
    nNode->next = 0;

    if (head == null)
    {
        head = nNode;
    }
    else
    {
        ListNode* tail = head;
        while (tail->next != 0)
        {
            tail = tail->next;
        }
        tail->next = nNode;
    }

    return head;
}

Or something like this. Its been quite some time since I last created linkedlist.

Wrath
  • 673
  • 9
  • 32
  • Your code looks more like Java (style-wise), and you are making `null` lowercase when it should be uppercase. – ktm5124 Mar 12 '13 at 06:34
  • I don't see the problem with checking whether `head` is NULL on the first iteration of the while loop. As you see, it works the first time in `main`. – ktm5124 Mar 12 '13 at 06:34
0

Modify the way you printing the list:

void print_list(ListNode* node)
{
    while (node)
    {
        cout << node->data << endl;
        node = node->next;
    }
}

reset cin before second read_list:

cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');

The program crashed will solve.

masoud
  • 55,379
  • 16
  • 141
  • 208