DaniWeb IT Discussion Community

DaniWeb IT Discussion Community (http://www.daniweb.com/forums/index.php)
-   C (http://www.daniweb.com/forums/forum118.html)
-   -   Seg Fault ~ Linked List Delete (http://www.daniweb.com/forums/thread36661.html)

Mistro116 Dec 12th, 2005 12:22 am
Seg Fault ~ Linked List Delete
 
Hello, I get the following seg fault error when I try to delete the last node of the list. Does anyone know why? My delete function and high level function are included below: The seg fault only occurs when the if value in BeginQuizFirstTry detecting that CheckAnswer is not true or = 0. Can anyone tell me why this seg faults?

int Delete (NODEPTR *headPtr, char *target)
{
  /*  Node pointers that reference the previous node
      and the current node in the list.              */
  NODEPTR prev = NULL, curr = NULL;
   
  /*  Check to see if the list is empty.  */
  if (IsEmpty (*headPtr))
  {
      /*  Display an appropriate message indicating that
          deleting from the list was not accomplished
          because the list is empty.                      */
      fprintf (stderr, "Unable to delete from an empty list.\n\n");
     
      /*  If the list is empty, return the integer value
          of -1, indicating that the question, char
          *target, was not successfully deleted from the
          list.                                          */
      return (-1);
  }
  /*  Traverse the list until the target value is found.  */
  else
  {
      /*  Initialize the node pointer referencing a previous
          node in the list to NULL.                          */
      prev = NULL;
     
      /*  Set the node pointer referencing a current node to
          the head of the list.                              */
      curr = *headPtr;
     
      /*  First check to see if the question, char *target,
          that we want to delete is stored in the first
          node in the list, because this would require
          *headPtr to be modified.                          */
      if (strcmp ((*headPtr) -> data.question, target) == 0)
      {
        /*  If the question, char *target, is stored in the
            first node in the list, change the head of the
            list to start at the node pointer referencing
            the current node's next pointer.                */
        *headPtr = curr -> next;
       
        /*  Delete and free the memory that was being used
            to store the question, char *target, in the
            first node of the list.                        */
        free (curr);
       
        /*  If the question, char *target, was freed and
            deleted, return the integer value of 1,
          indicating that the question was successfully
          deleted from the list.                        */
        return (1);
      }
      /*  Otherwise, traverse through the list to find the
          question, char *target, to be deleted.            */
      else
      {
        /*  Traverse the list if the node pointer
            referencing the current node in the list is not
            equal to NULL and the node pointer referencing
            the current node in the list is not storing the
            question, char *target, in the data portion of
            its node.                                        */
        while ((curr != NULL) &&
                (strcmp (curr -> data.question, target) != 0))
        {
            /*  Traverse the list.  */
            prev = curr;
            curr = curr -> next;
        }
       
        /*  If the node pointer refencing the current node in
            the list not equal to NULL, then the question,
            char *target, was found.                          */
        if (curr != NULL)
        {
            /*  Change the next pointer of the previous node,
                in order to avoid a broken list.              */
            prev -> next = curr -> next;
           
            /*  Delete and free the memory that was being used
                to store the question, char *target, in this
                node of the list.                              */
            free (curr);
           
            /*  If the question, char *target, was freed and
                deleted, return the integer value of 1,
                indicating that the question was successfully
                deleted from the list.                        */
            return (1);
        }
        /*  Otherwise, the question, char *target, was not
            found in the list.                              */
        else
        {
            /*  If the question, char *target, was not found
                in the list, return the integer value of -1,
                indicating that the question was not
                successfully deleted from the list.          */
            return (-1);
        }
      }
  }
}

int BeginQuizFirstTry (NODEPTR *headListPtr1,
                      NODEPTR *headListPtr2,
                      int numberOfTotalQuestions)
{
  /*  A node pointer that will reference the current node
      in the list, starting with the head pointer of the
      first list.                                          */
  NODEPTR curr = *headListPtr1;
 
  /*  A node pointer that will reference a temporary node
      in the list, which will be used for inserting nodes
      into the second list.                                */
  NODEPTR temp;
 
  /*  An array of characters, or a string, which will hold
      the answer that the user inputted for the given
      question that he/she was being asked during the quiz.  */
  char questionAnswer [NUMBEROFANSWERCHARACTERS];
 
  /*  An integer counter variable that will be used to
      label each of the questions in the quiz.          */
  int questionCounter = 0;
 
  /*  An integer counter variable that will be used to
      count the number of questions that the user answered
      correctly during his/her trial of taking the quiz.    */
  int correctAnswerCounter = 0;
 
  /*  A QUIZ structure that will be used to insert each
      question from the first list, into the second list.  */
  QUIZ insertedQuestion;
 
  /*  A float variable that will be used to store the
      user's percentage of correct answers during the
      user's first trial of taking the quiz.          */
  float scoreTrial1;
 
  /*  Display a message indicating that the quiz has
      begun for the user.                            */
  printf ("Here are your questions. Good luck !!!\n\n");
 
  /*  Traverse the list until the end.  */
  while (curr != NULL)
  {
      /*  Increment questionCounter each time a new question
          from the quiz is presented to the user.            */
      questionCounter++;
     
      /*  Display each of the questions in the quiz to the
          user.                                            */
      printf ("  %d. ", questionCounter);
      DisplayQuestion (curr);
     
      /*  Read in the user's answer for each of the questions
          in the quiz.                                        */
      scanf ("%s", questionAnswer);
     
      /*  If the user's answer is not correct, then delete it
          from the first list and insert it into the second
          list.                                                */
      if (CheckAnswer (curr, questionAnswer,
                      &correctAnswerCounter) != 1)
      {
        /*  Copy the original question and correct answer that
            the user was just being asked into the QUIZ structure,
            insertedQuestion.                                      */
        strcpy (insertedQuestion.question, curr -> data.question);
        strcpy (insertedQuestion.answer, curr -> data.answer);
       
        /*  Create enough space in memory for a temporary node
            that will be inserted into the second list.        */
        temp = CreateNode ();
       
        /*  Store the contents of the original question and
            correct answer that the user was just being asked
            into the data portion of the temporary node that
            was just created.                                  */
        SetData (temp, insertedQuestion);
       
        /*  Insert the temporary node into the second list.  */
        Insert (headListPtr2, temp);
       
        /*  Free the memory that was used to create the temporary
            node.                                                  */
        free (temp);
       
        /*  Set the node pointer referencing the current node
            (the current question in the quiz) to point to the
            next node in the list, or the next question in the
            quiz.                                              */
        curr = curr -> next;
       
            /*  Delete the question and its correct answer,
                which was just asked to the user, from the first
                list.                                            */
            Delete (headListPtr1, insertedQuestion.question);
      }
      else
      {
        /*  Set the node pointer referencing the current node
            (the current question in the quiz) to point to the
            next node in the list, or the next question in the
            quiz.                                              */
        curr = curr -> next;
      }
  }
 
  /*  Calculate the user's percentage of questions that were
      answered correctly during the first trial of the quiz.  */
  scoreTrial1 = CalculateScore ((float)correctAnswerCounter,
                                (float)numberOfTotalQuestions);
 
  /*  Display the user's score and tell him/her to retry the
      questions that were answered incorrectly.              */
  printf ("Your score is  %.2f%%\n", scoreTrial1);
  printf ("Improve your score by repeating the ones you missed.\n\n\n");
 
  /*  Return the number of questions that were answered
      correctly by the user during this trial so that the
      score can be recalculated in the second trial.      */
  return correctAnswerCounter;
}

Thanks in advance,
Mistro116

jim mcnamara Dec 12th, 2005 11:08 am
Re: Seg Fault ~ Linked List Delete
 
After a ver quick look, I think that you overwrote a pointer - having it point to a bogus address.

malloc works (It's called Doug Lea malloc which is the basis for many versions of malloc) kinda like this:
typedef
union
{
    ptrdiff_t malloc_size;
    void *ptr;
} malloc_t;
The malloc routine returns ptr to your program. When you call free later on, it assumes there is a value in the address immediately "underneath" the pointer. And that it is the same value you started with. Well, if ptr was changed, the value under it could be 0xfffffff, or literally anything else. When free tries to work with the block referenced by ptr, it bumps into memory your process does not own because:

1. ptr references memory you don't own or is read-only
2. malloc_size is the forcing free to reference memory you don't own or is read-only.

Mistro116 Dec 12th, 2005 6:58 pm
Re: Seg Fault ~ Linked List Delete
 
Quote:

Originally Posted by jim mcnamara
After a ver quick look, I think that you overwrote a pointer - having it point to a bogus address.

malloc works (It's called Doug Lea malloc which is the basis for many versions of malloc) kinda like this:
typedef
union
{
    ptrdiff_t malloc_size;
    void *ptr;
} malloc_t;
The malloc routine returns ptr to your program. When you call free later on, it assumes there is a value in the address immediately "underneath" the pointer. And that it is the same value you started with. Well, if ptr was changed, the value under it could be 0xfffffff, or literally anything else. When free tries to work with the block referenced by ptr, it bumps into memory your process does not own because:

1. ptr references memory you don't own or is read-only
2. malloc_size is the forcing free to reference memory you don't own or is read-only.

Thanks, but that has nothing to do with my function. I've malloc'd the data for the node, the pointer is returned fine. That's not the problem. The problem is the segmentation fault at the end of the list. I've come up with some new code, using this delete function.

Can anyone tell me why this doesn't delete the items in the list are wrong when CheckAnswer is evaluated:

int BeginQuizFirstTrial (NODEPTR *headListPtr1,
                        NODEPTR *headListPtr2,
                        int numberOfTotalQuestions)
{
  /*  A node pointer that will reference the current node
      in the list, starting with the head pointer of the
      first list.                                          */
  NODEPTR curr = *headListPtr1;
 
  /*  A node pointer that will reference a temporary node
      in the list, which will be used for inserting nodes
      into the second list.                                */
  NODEPTR temp;
 
  /*  An array of characters, or a string, which will hold
      the answer that the user inputted for the given
      question that he/she was being asked during the quiz.  */
  char questionAnswer [NUMBEROFANSWERCHARACTERS];
 
  /*  An integer counter variable that will be used to
      label each of the questions in the quiz.          */
  int questionCounter = 0;
 
  /*  An integer counter variable that will be used to
      count the number of questions that the user answered
      correctly during his/her trial of taking the quiz.    */
  int correctAnswerCounter = 0;
 
  /*  A QUIZ structure that will be used to insert each
      question from the first list, into the second list.  */
  QUIZ insertedQuestion;
 
  /*  A float variable that will be used to store the
      user's percentage of correct answers during the
      user's first trial of taking the quiz.          */
  float scoreTrial1;
 
  /*  Display a message indicating that the quiz has
      begun for the user.                            */
  printf ("Here are your questions. Good luck !!!\n\n");
 
  /*  Traverse the list until the end.  */
  while (curr != NULL)
  {
      /*  Increment questionCounter each time a new question
          from the quiz is presented to the user.            */
      questionCounter++;
     
      /*  Display each of the questions in the quiz to the
          user.                                            */
      printf ("  %d. ", questionCounter);
      DisplayQuestion (curr);
     
      /*  Read in the user's answer for each of the questions
          in the quiz.                                        */
      scanf ("%s", questionAnswer);
     
      /*  If the user's answer is not correct, then delete it
          from the first list and insert it into the second
          list.                                                */
      if (CheckAnswer (curr, questionAnswer,
                      &correctAnswerCounter) != 1)
      {
        /*  Copy the original question and correct answer that
            the user was just being asked into the QUIZ structure,
            insertedQuestion.                                      */
        strcpy (insertedQuestion.question, curr -> data.question);
        strcpy (insertedQuestion.answer, curr -> data.answer);
       
        /*  Create enough space in memory for a temporary node
            that will be inserted into the second list.        */
        temp = CreateNode ();
       
        /*  Store the contents of the original question and
            correct answer that the user was just being asked
            into the data portion of the temporary node that
            was just created.                                  */
        SetData (temp, insertedQuestion);
       
        /*  Insert the temporary node into the second list.  */
        Insert (headListPtr2, temp);
       
        /*  Set the node pointer referencing the current node
            (the current question in the quiz) to point to the
            next node in the list, or the next question in the
            quiz.                                              */
        curr = curr -> next;
       
        /*  Make sure the node pointer referencing the current
            node (the current question in the quiz) contains
            a node and is not beyond the end of the first list.  */
        if (curr != NULL && curr -> next != NULL)
        {
           
            /*  Delete the question and its correct answer,
                which was just asked to the user, from the first
                list.                                            */
            Delete (headListPtr1, insertedQuestion.question);
        }
      }
      else
      {
        /*  Set the node pointer referencing the current node
            (the current question in the quiz) to point to the
            next node in the list, or the next question in the
            quiz.                                              */
        curr = curr -> next;
      }
  }
 
  /*  Destroy the first list and all of its contents, and free
      all of the memory that was allocated to store the node
      data once the user has been asked all of the questions in
      the quiz read from the data file containing the original
      list of questions and correct answers.                    */
  DestroyList (headListPtr1);
 
  /*  Calculate the user's percentage of questions that were
      answered correctly during the first trial of the quiz.  */
  scoreTrial1 = CalculateScore ((float)correctAnswerCounter,
                                (float)numberOfTotalQuestions);
 
  /*  Display the user's score and tell him/her to retry the
      questions that were answered incorrectly.              */
  printf ("Your score is  %.2f%%\n", scoreTrial1);
  printf ("Improve your score by repeating the ones you missed.\n\n\n");
 
  /*  Return the number of questions that were answered
      correctly by the user during this trial so that the
      score can be recalculated in the second trial.      */
  return correctAnswerCounter;
}

Thanks though,

Mistro116


All times are GMT -4. The time now is 11:37 pm.

Forum system based on vBulletin Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
©2003 - 2009 DaniWeb® LLC