views:

169

answers:

3

Hey everyone, I am new to C and I am working on an XOR linked list for a project. I have most of the code done, but I can't seem to get the delete function of the list to work properly. It seems able to delete some numbers, but not any number you pass into the function. Could anyone experienced with C take a look and possibly point out where I went wrong? I have been working on this for a while now and have not had much luck and I have started over 3 times :( Any help is much appreciated. Thank you. You can see my first attempt of code here. I can only post one link, so if you would like to see my second attempt, just tell me so and I can email it to you or something. Thank you for your time.

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

struct node {
       int data;
       unsigned long link;
};
struct node *head, *tail, *currN, *prevN, *nextN, *tmp;

void insert(struct node **headN, struct node **tailN, int n);
void delete(struct node **headN, struct node **tailN, int n);
void list(struct node *head, int i);
void nextNode();
void previNode();

//============================================================

void insert(struct node **headN, struct node **tailN, int numN) {
     struct node *newnode = malloc(sizeof(struct node));
     newnode->link =(unsigned long)(*headN);
     newnode->data = numN;

     //if empty list
     if (*headN == NULL){
          *headN = newnode;
          currN = *headN;
          (*headN)->link = 0;
     } else if ((*headN)->link == (unsigned long)NULL){
           if (numN <= (*headN)->data){
                newnode->link = (unsigned long) *headN;
                (*headN)->link = (unsigned long) newnode;
                tail = *headN;
                *headN = newnode;
                nextN = tail;
                prevN = NULL;
            } else {
                newnode->link = (unsigned long) *headN;
                (*headN)->link = (unsigned long) newnode;
                tail = newnode;
                nextN = NULL;
                currN = tail;
                prevN = *headN;
              }
     } else { 
          currN = *headN;
          prevN = NULL;
          nextN = (struct node *)(currN->link ^ (unsigned long) prevN);
          if (numN > tail->data){
               while (currN!=tail){
                     nextNode();
               }
               newnode->link = (unsigned long) currN;
               currN->link = (unsigned long) newnode ^ (unsigned long) prevN;
               tail = newnode;
          } else if (numN < head->data){
               currN->link = (unsigned long) newnode ^ (unsigned long) nextN;
               newnode->link = (unsigned long) currN;
               *headN = newnode;
               nextN = currN;
               currN = *headN;
          } else {
               while (numN > currN->data){
                     nextNode();
               }
               newnode->link = (unsigned long) prevN ^ (unsigned long) currN;
               prevN->link ^= (unsigned long) currN ^ (unsigned long) newnode;
               currN->link ^= (unsigned long) prevN ^ (unsigned long) newnode;
          }
     }
}  

void delete(struct node **headN, struct node **tailN, int numD){

     struct node *prevN = NULL;
     struct node *currN = *headN;

     while ( currN != NULL )
    {
        struct node *nextN = (struct node *) (currN->link ^ (unsigned long)prevN);  
        //if the number is found, then delete it
        if (currN->data == numD)
        {
          if(prevN) 
                  {
                     prevN->link ^= (unsigned long)currN ^ (unsigned long)nextN;
              }
                  else 
                     *headN = nextN;
              if(nextN) 
                  {
                     nextN->link ^= (unsigned long)currN ^ (unsigned long)prevN;
                  } 
                  else 
                     *tailN = prevN;
          free(currN);
          break;
        }
            prevN = currN;
        currN = nextN;
    }
}

void list(struct node *head, int i){

    if(i == 0){ 
     currN = head;
     prevN = NULL;
     int count = 1;
     nextN = (struct node *) (currN->link ^ (unsigned long) prevN);
     printf("Linked List in ascending order\n");
     while(currN!=NULL){
          if(count <= 10){
               printf("%-5d", currN->data);
               nextNode();
               count++;
          } 
          else{
               printf("\n");
               count = 1;
          }
     }
    }
     printf("\n\n"); 

    if(i == 1){ 
     printf("Linked List in descending order\n");
     currN = tail;
     int count2 = 1;
     prevN = (struct node *) currN->link;
     nextN = NULL;
     while (currN!=NULL){
         if(count2 <= 10){
              printf("%-5d", currN->data);
              previNode();
              count2++;

          }else{
              printf("\n");
              count2 = 1;
          }
     } 
    }   
    printf("\n");         
}

void nextNode(){
    nextN = (struct node *) (currN->link ^ (unsigned long) prevN);
    prevN = currN;
    currN = nextN;
}

void previNode(){
    prevN = (struct node *) (currN->link ^ (unsigned long) nextN);
    nextN = currN;
    currN = prevN;      
}

int main(){

    int i, num;
    float seed;
    head = NULL; tail = NULL; currN = NULL; prevN = NULL; nextN = NULL;

    init_seed(1234567);
    set_range(1,9999);
    //inserting data into the linked list
    for ( i=0; i<100; ++i){
        num = rndm();
        insert( &head, &tail, num );
    }

    list((struct node*)head, 0);
    //delete((struct node**)head, (struct node**)tail, 45);
    //delete((struct node**)head, (struct node**)tail, 4040);
    //delete((struct node**)head, (struct node**)tail, 9769);
    list((struct node*)head, 1);


    return 0;
}
A: 

A note about your code:

The node.link should not be a unsigned long it since this assumes characteristics of you compiler/platform.

EDIT: Maybe I missed out on the XOR linked list, discussion.

EDIT 2: (as suggested by @Matthew Flaschen) use intptr_t to make your code more portable.

Rickard von Essen
Why should it be a `struct node *`? And it should be a comment.
Bertrand Marron
@tusbar Ok, with an XOR linked list is maybe not that easy, but it looks like the code assumes that the size of a reference to a node i of the same size as an unsigned long int, which is only true on some platforms/compilers.
Rickard von Essen
That's true, on LLP64 `sizeof(ptr)` is 64 bits and `sizeof(long)` is 32.
Bertrand Marron
As noted, he requires some type-unsafety due to the XOR linked list. But `intptr_t` would be a better type, which you may want to note in your answer.
Matthew Flaschen
+4  A: 

It looks like you took some code on the internet and tried to use it.

The code works just fine, you just don't know what a pointer is.

You're doing:

delete((struct node**)head, (struct node**)tail, 45);

And here are the definitions of the variables head and tail:

struct node {
  int data;
  unsigned long link;
};
struct node *head, *tail, *currN, *prevN, *nextN, *tmp;

The prototype for the delete() function is void delete(struct node **headN, struct node **tailN, int numD);

"Oh the compiler is asking for struct node **, let's cast it". That's not how it works.

Try this:

delete(&head, &tail, 45);
Bertrand Marron
seePhor
http://codepad.org/wWW5ZUHS
Bertrand Marron
what did you do/change?
seePhor
Only the `main()` function.
Bertrand Marron
A: 

Looking at the delete function makes me wonder about this pointer manipulation, by the way, you are using address-of parameters so really it should be delete(&head, &tail, 45);

moving on from that....

void delete(struct node **headN, struct node **tailN, int numD)
{
   struct node *prevN = NULL;
   struct node *currN = *headN; 
   struct node *tempNode = NULL;

   while ( currN != NULL )
   {
      struct node *nextN = (struct node *) (currN->link ^ (unsigned long)prevN);  
      //if the number is found, then delete it
      if (currN->data == numD)
      {
          if(prevN)
             prevN->link ^= (unsigned long)currN ^ (unsigned long)nextN;
          else 
             *headN = nextN;
          if(nextN)
             nextN->link ^= (unsigned long)currN ^ (unsigned long)prevN;
          else
             *tailN = prevN;
          /* Sanity check here...you could be screwing up the list 
          ** by calling free(currN)
          */
          tempNode = currN;
          free(tempNode);
          /* free(currN); <-- That could be misleading... */
          break;
       }
       prevN = currN;
       currN = nextN;
   }
}

That amendment to the code is to ensure that currN is consistent, looking at with eyes on the pointer manipulation, that could be questionable, as the list could end up broken by doing a free on the currN...just to be safe...

tommieb75
I'm not seeing what your amendment does. currN is being deleted from the list, so the node is being freed. You do the same thing, just with an extra pointer variable. Of course, the `prevN = currN; currN = nextN;` don't execute due to the `break` (in this case, the break is effectively a `return`)
Matthew Flaschen
This worked! So what problems was free(currN) causing exactly?
seePhor
@seePhor: I was actually thinking of when iterating through a linked list like ''while (currN != null)', that currN could end up being freed and break the while loop...hence the need to temporarily assign it to another pointer to free up... tempNode = currN; currN = currN->next; free(tempNode); perhaps I got mixed up...and thought that would apply here...
tommieb75