Linked LIst sorting and Segmentation Fault - c

I am currently working on a program which is meant to hold inventory for a watercraft rental company. This program uses a linked list to hold the data about the inventory. I have gotten all of the functions to work other than print by price. This function is meant to sort the linked list in order of lowest to highest price and then print the list. I think that my sorting algorithm is alright but I am getting a seg fault that I can not find the cause of. Any help is appreciated. The following code is my print by price function.
//creates a new list and copies every number from inventory over to this one
//except add the values in order from lowest to highest by adding in order
int i = 0;
//initialize new list
list_t *sorted = (list_t*)malloc(sizeof(list_t));
sorted->size = list->size;
sorted->head = NULL;
sorted->tail = NULL;
//make temp variable for iteration
watercraft_t *init = list->head;
watercraft_t *temp = list->head;
watercraft_t *prev = NULL;
for(i = 0; i < list->size; ++i){
watercraft_t *new = (watercraft_t*)malloc(sizeof(watercraft_t));
new = init;
if(sorted->head == NULL){
new = sorted->head;
new->next = NULL;
}
else if(new->total_price < temp->total_price){
prev->next = new;
new->next = temp;
}
else if(temp->next == NULL){
temp->next = new;
new->next = NULL;
}
prev = temp;
temp = temp->next;
init = init->next;
}
This is the structure which is within the linked list holding the data
typedef struct watercraft {
char type[15]; // e.g. pontoon, sport boat, sailboat, fishing,
// canoe, kayak, jetski, etc.
char make[20];
char model[30];
int propulsion; // 0 = none; 1 = outBoard; 2 = inBoard;
char engine[15]; // Suzuki, Yamaha, etc.
int hp; // horse power
char color[25];
int length; // feet
double base_price;
double total_price;
accessories_t extras;
struct watercraft *next;
} watercraft_t;
If there is any other code that is necessary for this problem please let me know. There are about 400 more lines of code for this project.

Related

Why aren't new elements being added to my linked list?

This is just a snippet of the code, but I checked and know for a fact that all the strings save nicely into the "new" element (in function SortedInsert), but then the "new" doesn't link to the head?
I've tried everything I could think, hopefully I'm just missing something obvious.
typedef struct _Info* Position;
typedef struct _Info{
char name[MAX];
char surname[MAX];
Position next;
} Info;
(declaration inside main function:
Info headInfo = {.name = {0}, .surname {0}, .next = NULL};
Position head = &headInfo;
)
int SortedInsert(Position head, char name[], char surname[]){
Position prev = NULL, temp = NULL, new = NULL;
prev = head;
temp = head->next;
new = (Position)malloc(sizeof(Info));
if(!new){
return EXIT_FAILURE;
}
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
if(head->next==NULL){
temp = new;
}
else{
// first sort, by surname
while(strcmp(temp->surname, new->surname) < 0){
prev = temp;
temp = temp->next;
}
// second sort, by name
while(strcmp(temp->name, new->name) < 0){
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
}
return EXIT_SUCCESS;
}
int PrintList(Position head){
Position temp = NULL;
temp = head->next;
while(temp){
printf("%s ", temp->name);
printf("%s\n", temp->surname);
printf("---\n");
temp = temp->next;
}
return EXIT_SUCCESS;
}
Some issues:
temp = new does not insert anything into the list. It merely copies a reference to the new node into a local variable. The assignment should be to head->next. Moreover, there is no need to create a separate case for this. It can be handled with the code you have in the else part.
The retrieval of the insert point is not correct. If in the first loop the strcmp call returns 1 (not 0), then the second while loop should not iterate at all: it doesn't matter in that case what the first name is like. The last name of temp is already greater, so the insertion point has been found. Similarly, if the strcmp call returns 0, the second loop should keep verifying that the last name is still the same in its second iteration,...etc. Moreover, this logic can be combined in one loop.
Not a problem for the correct execution, but still:
Many consider it bad practice to typedef a pointer to a struct where you dereference the pointer regularly in your code. See the answers to Is it a good idea to typedef pointers? for some background. So I'd keep using Info *.
Create a separate function for creating and initialising a node.
The comments that say "first sort", "second sort" are misleading. There is no sorting happening in the loop that follows the comment. The list is already sorted. The process that follows just intends to find the insertion spot according to the sort order. So the comment could be improved.
Many consider it better not to cast the value returned by malloc.
Here is the correction of the SortedInsert function, together with the separated function for node creation:
Info *createNode(char name[], char surname[]) {
Info *new = malloc(sizeof(*new));
if (new != NULL) {
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
}
return new;
}
int SortedInsert(Info *head, char name[], char surname[]){
Info *new = createNode(name, surname);
if (new == NULL) {
return EXIT_FAILURE;
}
Info *prev = head;
Info *temp = head->next;
// Find insertion spot according to sort order
while (temp != NULL) {
int cmp = strcmp(temp->surname, new->surname);
if (cmp == 0) { // It's a tie. Then use name as discriminator
cmp = strcmp(temp->name, new->name);
}
if (cmp >= 0) { // Found insertion spot
break;
}
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
return EXIT_SUCCESS;
}

Wrong value when inserting into a linked list in c

I am trying to insert words into a hash table and it looks like it works but when I try to print the word inside the node (just to check if its still correct) I get a bogus value. When my code prompts for the word I said 'Hey' and when it prompts for place I said '5'. The string that is printed out(which is supposed to be the word inside the node) is HH9[]A\A]A^A_f. What is happening to the word inside the node and am I inserting the node correctly?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
int main (void)
{
node* table[10];
char wrd[10];
printf("Word to insert: ");
fgets(wrd, 10, stdin);
int place;
printf("Place to insert word: ");
scanf("%d", &place);
node *n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
if(table[place] == NULL)
{
n = table[place];
n->next = NULL;
}
else
{
n->next = table[place];
n = table[place];
}
printf("Word inside node: %s \n" , n->word);
}
EDIT
I changed the code and tried to implement it on a larger scale but my while loop gives me a segfault. This is the function I put it in:
FILE* dct = fopen ("/dictionaries/large", "r");
char *wrd = NULL;
while(fscanf(dct, "%s", wrd) != EOF)
{
int place = hash(wrd);
node *n = malloc(sizeof(node));
node *anchor = NULL;
node *end = NULL;
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
n->next = NULL;
if (!end) //Initial state
anchor = end = n;
else //Every following node.
end = end->next = n;
strcpy(n->word, wrd);
n->next = table[place];
table[place] = n;
counter++;
}
return false;
It has to read from the dictionary file and load the word into memory(or a hash table).
A linked list is a linked list because it does not have a fixed size.
The table array is therefor superfluous.
What you need for your linked list to work is to remember the anchor and nothing more.
A small example:
Node *anchor = NULL;
Node *end = NULL;
Node *node = malloc(sizeof(Node));
node->next = NULL;
if (!end) //Initial state
anchor = end = node;
else //Every following node.
end = end->next = node;
At this point, you can still access the node you've just filled. Don't forget to iterate over your list later and free those allocations though.
This code doesn't make any sense:
if(table[place] == NULL)
{
n = table[place]; // since we know table[place] is null, that sets n to null!
n->next = NULL; // We just set n to NULL, we can't access n->next!
}
else
{
n->next = table[place]; // This sets n to a garbage value since table[place] was never assigned a value
n = table[place]; // This leaks the value we malloc'ed. We were supposed to link it to the list!
}

Sorting doubly linked list alphabetical

The task is to sort a list in alphabetical order. That is to be done by changing the pointer variables and not just switching the content of the nodes.
I first wanted to implemend a swap function. that function shall swap 2 nodes. After that I wanted to implement a sorting algorithm. My problem is, that the swaping function does not really work as it should and the algorithm doesnt either (ofc, since the swapping function doesnt even work).
struct student {
char Vorname[51];
char Nachname[51];
int MatNr;
char Adresse[51];
int Kurse;
struct student *next;
struct student *previous;
};
struct student *first = NULL;
struct student *last = NULL;
void swap(struct student *pointer) {
struct student *pointer1, *pointer3, *pointer4;
pointer1 = pointer->previous;
pointer3 = pointer->next;
pointer4 = pointer->next->next;
pointer4->previous = pointer;
pointer->next = pointer4;
pointer1->next = pointer3;
pointer3->previous = pointer1;
pointer->previous = pointer3;
pointer3->next = pointer;
}
This is the not finished sort function. I didnt implement it correctly yet, since the swap function took my attention first.
void sort(void) {
struct student *pointer1, *pointer2, *pointer3, *pointer4;
pointer1 = first->previous;
pointer2 = pointer1->next;
pointer3 = pointer2->next;
pointer4 = pointer3->next;
while(pointer2 != NULL){
if((strcmp(pointer2->Nachname, pointer3->Nachname)) > 0) {
swap(pointer2);
}
pointer1 = pointer1->next;
printList();
}
}
When I run swap(first); the first element doesnt get displayed since the pointer first is now pointing at the second node. Well, thats easily done with first = pointer3;
When I run swap(first->next); there is a similar problem, since it also leaves out one node of the list.
I'm not really sure how to get this function right, since first shouldnt get involved in swapping the 2nd and 3rd node of the list.
I'd appreciate any help that could help me solving this, maybe I'm just overlooking some minor mistake, but I can't really get the solution of this.
Thank you!
Sorting the list by swapping doubly linked nodes seems quite inefficient because you cannot use fast algorithms like merge sort.
You could instead use only the next links in a recursive merge sort function and reconstruct the back links on the resulting list.
Here is how to do it:
struct student {
char Vorname[51];
char Nachname[51];
int MatNr;
char Adresse[51];
int Kurse;
struct student *next;
struct student *previous;
};
struct student *first = NULL;
struct student *last = NULL;
/* Merge two sorted lists. p1 and p2 are != NULL */
struct student *merge(struct student *p1, struct student *p2) {
struct student *head, **pp;
pp = &head;
for (;;) {
if (strcmp(p1->Nachname, p2->Nachname) <= 0) {
*pp = p1;
pp = &p1->next;
p1 = p1->next;
if (p1 == NULL) {
*pp = p2;
break;
}
} else {
*pp = p2;
pp = &p2->next;
p2 = p2->next;
if (p2 == NULL) {
*pp = p1;
break;
}
}
}
return head;
}
/* Recursive top-down merge sort */
struct student *msort(struct student *np) {
struct student *p1, *p2;
/* trivial lists are sorted */
if (np == NULL || np->next == NULL)
return np;
/* locate mid-point using 2 finger method */
for (p1 = np, p2 = np->next; p2 && p2->next; p2 = p2->next->next)
p1 = p1->next;
/* split the list at mid-point */
p2 = p1->next;
p1->next = NULL;
p1 = np;
/* sort the sublists recursively */
p1 = msort(p1);
p2 = msort(p2);
return merge(p1, p2);
}
void sort(void) {
struct student *p1, *p2;
/* sort the list as a singly linked list */
first = msort(first);
/* reconstruct the backlinks */
p1 = NULL;
for (p2 = first; p2; p2 = p2->next) {
p2->last = p1;
p1 = p2;
}
last = p1;
}
As suggested by rcgldr, it may be more efficient to use a bottom-up merge sort to avoid repeated scans of the lists. Here is the alternate code:
/* bottom-up merge sort with sublist array */
struct student *msort(struct student *head) {
struct student *array[32] = { NULL };
int i;
/* handle trivial lists */
if (head == NULL || head->next == NULL)
return head;
i = 0; /* avoid warning */
p1 = head;
/* merge nodes into pending lists of increasing lengths */
while (head != NULL) {
struct student *next = head->next;
head->next = NULL;
for (i = 0; i < 32 && array[i] != NULL; i++) {
head = merge(array[i], head);
array[i] = NULL;
}
/* do not go past end of array */
if (i == 32)
i--;
array[i] = head;
head = next;
}
/* merge pending lists into single list:
* the last element stored into the array is at offset i and
* all entries before it are NULL pointers. */
for (head = array[i++]; i < 32; i++) {
if (array[i] != NULL)
head = merge(array[i], head);
}
return head;
}

Creating a sublist of the original list?

I'm trying to make a function that takes two parameters positions to take from list and original list and then copy indexed numbers to a list. Also i included the Struct for the list and the head. I get the EXC_BAD_ACCESS Error i commented the line.
code:
struct node_struct {
Item item;
link next;
};
struct list_struct {
link first;
int length;
};
list sublist(list A, list pos_list) {
int index = 0;
link tempForindex = malloc(sizeof *tempForindex);
link temp2 = malloc(sizeof *temp2);
list finale = malloc(sizeof *finale);
link temp3 = malloc(sizeof *temp3);
tempForindex = pos_list->first;
temp2 = A->first;
temp3 = finale->first;
int counter = 0;
while(tempForindex->next != NULL)
{
index = tempForindex->item;//EXC_BAD_ACCESS code1
counter = 0;
while(temp2->next != NULL)
{
if (counter == index)
{
temp3->item = temp2->item;
temp2 = A->first;
temp3 = temp3->next;
break;
}
temp2 = temp2->next;
counter++;
}
tempForindex = tempForindex->next;
}
return finale;
}
It all hopelessly flawed.
You need to get patterns going with linked lists. The structures are fine, but the fact that the code is crashing in the position indicated suggests to me that pos_list has not been set up correctly.
iterate through a list using this pattern
list mylist;
link ptr;
for(ptr = mylist->first; ptr != NULL; ptr = ptr->next)
{
/* loop body */
}
now write a test function to print out both arguments and ascertain that they are valid.

c bubblesort a link list

trying to get a function to run that will bubble sort a link list from smallest to largest number. I don't want the data to be moved around in the link list instead have the pointers be pointing elsewhere in case each link needs to hold a lot of data.
In each link I have a INT arrivalTime field that will house a integer value. THis number determines where the link should be in the list.
My program seems to hang at the moment, I'd appreciate if anyone could fix it up, Thanks
bubble sort function
void bubbleSort(struct order *start)
{
int swapped, i;
processData *current = start;
processData *temp;
struct order *lptr = NULL;
/* Checking for empty list */
if (current == NULL)
printf("null \n");
do
{
swapped = 0;
current = start;
while (current->next != lptr)
{
if (current->arrivalTime > current->next->arrivalTime)
{
temp = current;
current = current->next;
current->next = temp;
swapped = 1;
}
current = current->next;
}
lptr = current;
}
while (swapped);
}
structure of link list
struct order
{
int name;
int arrivalTime;
int quanta;
struct order * next;
};
typedef struct order processData;
Swapping two adjacent items in a singly-linked-list requires that you change three next pointers.
If the order is A --> B --> C --> D and you swap B with C to get A --> C --> B --> D then
A->next needs to point to C instead of B
B->next needs to point to D instead of C
C->next needs to point to B instead of D
This is a very slow thing you're trying to do - see this paper on comparing ways to sort a linked list.
Currently, your algorithm will never terminate because in your while loop, you set lptr = current, but then test whether current->next == lptr. This will never return true unless one of your list members points to itself.
If you do have a definite use case to bubble sort the linked list, consider this: The purpose of a linked list is that you access it by working sequentially from the list head to the item you want. If your initial list head is not the smallest or the largest and you're only changing pointers, you need to keep track of where the head of the list is.
I did think of a way to do it loosely based on yours, see below. Sorry it's a bit messy - I'm not a C expert (hope the memory allocation is OK...) and I'm sure there are optimisations. In particular I'm sure there are better ways to pass the headOfList pointer back to the main algorithm. I've tested it for a number of 100 member lists of structs with some negative numbers. I've left the code to generate them with random arrival times in main() so you can just paste this in where your old code was and run it.
processData *bubbleSort(processData *start)
{
int swapped;
processData *current = start;
processData *lheadptr = start;
processData *previous = NULL;
processData *oldPrevButBigger;
processData *oldAfterThisPair;
/* Checking for empty list */
if (current == NULL)
{
printf("null \n");
return NULL;
}
do
{
swapped = 0;
current = lheadptr;
previous = NULL;
while (current->next) //Stop when current->next is null (i.e. end of list)
{
if (current->arrivalTime > current->next->arrivalTime)
{
oldPrevButBigger = current;
oldAfterThisPair = current->next->next;
current = current->next;
current->next = oldPrevButBigger;
current->next->next = oldAfterThisPair;
if (!previous)
{
//If no previous, this was the head of the list, so need to update
lheadptr = current;
}
else
{
// If there is a "previous", then we're not at head of list, so need
// to update that pointer too
previous->next = current;
}
swapped = 1;
}
previous = current;
current = current->next;
}
}
while (swapped);
return lheadptr;
}
int main()
{
srand(time(NULL));
int NUM = 100;
processData* pointToLast = NULL;
int i;
processData orders[NUM];
//Generate a list with random arrival times (last member of the list generated first
for (i = 0; i < NUM; i++ )
{
orders[i].name = i;
orders[i].arrivalTime = rand()-1000000000;
orders[i].quanta = 500;
orders[i].next = pointToLast;
pointToLast = &orders[i];
}
printf("List before\n");
printf("===========\n");
for (i=0; i < NUM; i++)
{
printf("%i;%i;%i\n", pointToLast->name, pointToLast->arrivalTime, pointToLast->quanta);
pointToLast = pointToLast->next;
}
processData* newListHead = bubbleSort(&orders[NUM-1]);
printf("List after\n");
printf("===========\n");
for (i=0; i < NUM; i++)
{
printf("%i;%i;%i\n", newListHead->name, newListHead->arrivalTime, newListHead->quanta);
newListHead = newListHead->next;
}
return 0;
}

Resources