0

This is a class assignment to do ordered insertion into a sorted linked list. I've avoided accessing null pointers, and I've added some lines of debugging output to narrow the seg fault down to the conditional statement of the while loop itself.

I can add a node to the empty list and add nodes with smaller keys to the head of the list, but I run into a seg fault when adding a key to the end of a non-empty list. As displayed by the debug output, the problematic while loop cycles successfully until it sees cursor->next == NULL. That's when it throws the seg fault. I'm not trying to access the empty pointer as far as I can tell. I'm really pretty stumped and would appreciate any help. Thanks!

I've denoted the troublesome line in the code below.

// Headers
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

struct Node {
  int id;
  string initials;
  double score;
  Node* next;
};
const int ESC = -9999;
const int ID_LIMIT = 1000000000;

int main(){  
  // initialize variables
  int temp_id = 0;  // temporary input
  Node* Start=NULL; // first node in linked list

  // get input until escape value is entered or input stream fails
  while ( temp_id != ESC && !cin.fail() ){
    cout << "\nPlease enter the student id, or "
         << ESC << " to finish inputing: ";
    cin >> temp_id;
    if ( temp_id >=0 && temp_id < ID_LIMIT ) { 
      // if valid input, continue input & create node
      string temp_inits;
      double temp_score;
      cout << "Please enter the student initials: " ;
      cin >> temp_inits;
      cout << "Please enter the student's test score: " ;
      cin >> temp_score;

      // create new node with input values
      Node* temp = new Node;
      temp->id = temp_id;
      temp->initials = temp_inits;
      temp->score = temp_score;
      temp->next = NULL;

      // TASK 4: SORTED INPUT
      if ( Start == NULL ) {  // if first node to be input
        Start = temp;         // point the first pointer to it
      }else{                  // otherwise
        if( temp->id < Start->id ){  // if new node should go before Start,
          temp->next = Start;        // move start after temp
          Start = temp;              // and reassign Start
        }else{
          Node* cursor = Start; // parse list for proper place or end
          cout << "\nDEBUG: while ( cursor-id:" << cursor->id ;
          cout << " < temp-id:" << temp->id;
          cout << " && cursor-next:" << cursor->next << " != NULL )";
// I THINK THE NEXT LINE IS THE CULPRIT
          while ( cursor->id < temp->id && cursor->next != NULL ) {
            cout << "\nDEBUG: { old cursor:" << cursor->id ;
            cursor = cursor->next;
            cout << ", new cursor:" << cursor->id << " }";
            cout << "\nDEBUG: while ( cursor-id:" << cursor->id ;
            cout << " < temp-id:" << temp->id;
            cout << " && cursor-next:" << cursor->next << " != NULL )";
          }
          cout << "\nDEBUG: insert temp-id:" << temp->id 
               << " after cursor-id:" << cursor->id ;
          temp->next = cursor->next;
          cursor->next = temp;  // inject new node into list.
          cursor = temp->next;
          cout << " before id " << cursor->id;
        }
      }
      cout << "Node with id=" << temp->id << ", initials=" << temp->initials 
           << ", and test score=" << temp->score << " added to the list.\n";

    }else{ // if invalid input & not escape value, print error
      if ( temp_id != ESC ) cout << "!!! Invalid input !!!\n";
    }   
  }

  return 0;
}

Output:

Please enter the student id, or -9999 to finish inputing: 654
Please enter the student initials: abc
Please enter the student's test score: 99.9
Node with id=654, initials=abc, and test score=99.9 added to the list.

Please enter the student id, or -9999 to finish inputing: 312
Please enter the student initials: qwe
Please enter the student's test score: 54.8
Node with id=312, initials=qwe, and test score=54.8 added to the list.

Please enter the student id, or -9999 to finish inputing: 987
Please enter the student initials: rty
Please enter the student's test score: 87.5

DEBUG: while ( cursor-id:312 < temp-id:987 && cursor-next:0x1c26040 != NULL )
DEBUG: { old cursor:312, new cursor:654 }
DEBUG: while ( cursor-id:654 < temp-id:987 && cursor-next:0 != NULL )
Segmentation fault

I have also tried the loop with ( ... cursor->next != 0 ) and ( ... cursor->next )

2
  • is it not just operator precidence in the while loop try while ( (cursor->id < temp->id) && (cursor->next != NULL) ) adding more parenthesis to make the condidtion unambiguous Commented Feb 22, 2012 at 0:05
  • @Dampsquid, I had the extra parentheses, but operator precedence should specifically render them unnecessary. Commented Feb 22, 2012 at 5:27

2 Answers 2

1
  while ( cursor->id < temp->id && cursor->next != NULL )
  {
      cursor = cursor->next;
  }

  temp->next = cursor->next;
  cursor->next = temp;  // inject new node into list.
  cursor = temp->next;
  cout << " before id " << cursor->id;

When the loop runs until cursor points at the last node, then cursor->next is null. After inserting the new node (it seems to me at wrong place, but no matter) the new node is last and has temp->next as nullpointer. Then cursor = temp->next sets cursor to null, and the debug output statement that follows, dereferencing cursor via cursor->id, crashes.

To be sure, I should run it in a debugger.

And that is one strong suggestion I have for you: use the debugger, not just the brains. :-)

Second strong suggestion: do use abstraction, do name just about everything in sight. Which means defining small functions, e.g. for list insertion. It’s much easier to analyze things then.

Sign up to request clarification or add additional context in comments.

3 Comments

Good catch, I stopped reading at cursor->id in the while :)
@Cheers-and-htf-alf, I'm not very savy with emacs yet, and the school computers don't allow user installation of sw. As for abstraction, that's usually my thing. Was hoping to just jam this out in an hour... re the crash point: if the program is crashing at the line temp->next = cursor->next; why doesn't the cout line immediately preceding that line print? As for placement, the cursor has not advanced, so it still points to either an node with id less than temp's or the last node, ergo, inserting temp after cursor will place it in the correct position.
I'm eating my words again: you were right about the wrong place. should have been checking against (cursor->next)->id ... need to think it out again before screwing up my cond. statement. Thanks for the help!
0

The problem is after you break out of the while() loop:

  1>    temp->next = cursor->next;
  2>    cursor->next = temp;  // inject new node into list.
  3>    cursor = temp->next;
  4>    cout << " before id " << cursor->id;

You reach the above lines with cursor->next == null (end of the list), and temp->next is also null. Line 1 therefore does nothing in this case. Line 2 copies temp's address into cursor->next. At this point we have:

temp: temp's original address, temp->next == NULL cursor: cursor's original address, cursor->next == temp's original address

Then you copy temp->next into cursor (uhoh!), but temp->next is null, so cursor now is null. So, when you go to execute line 4 and get cursor->id, it tries to read "null->id" and crashes.

3 Comments

lines 3 & 4 were added to debug this very issue (before I'd narrowed the problem upward). Regardless, I reiterate my response to @Cheers : if the crash happens where you note (which I admit, is an egregious error, and will edit tomorrow), then why does the cout line preceding line 1 not run?
you were right. I put lines 3 & 4 in an if (temp->next != NULL) block and it ran. My question regarding the cout line still stands though. Just boggles my mind. Thank you for the catch, btw.
Try cout-ing std::endl at the end of the cout statement that isn't happening. std::cout doesn't necessarily flush the buffer, so when you crash it has not yet actually output anything to the console. However, if you use std::endl, it will also flush the buffer and you should see the output.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.