Linked list printing & adding elements - c

So the idea is I have a Doubly linked list defined as a struct
struct Node
{
struct Node *next;
struct Node *prev;
char value[5];
};
struct DoubleLinkedList
{
int size;
struct Node *head;
struct Node *tail;
};
and I'm inserting into the list using the InsertionSort function. I pass the pointer to my Doubly Linked list as a parameter to that and it gets modified with the addition of a new 4 character string node to the list(lexicographically sorted Linked list). I then print the linked list with the addition of each string node.
The printing is proving to be problematic. Right now, with the code below, the output is always something like (assume the strings being inserted at every step are aaaa,bbbb,cccc...)
aaaa
bbbb -> bbbb
cccc -> cccc -> cccc
For some reason the linked list structure is changing each and every node to the value of the new string to be inserted; I have no idea why! And also, if I try shifting the print block to the main function, it prints out gibberish.
int main()
{
struct DoubleLinkedList strings;
while (1)
{
sleep(1);
char s[5];
GenerateRandomString(s,4);
InsertionSort(&strings, s);
}
return 0;
}
void InsertionSort(struct DoubleLinkedList *sorted, char *randomstring)
{
struct Node new;
strcpy(new.value,randomstring);
printf("Newvalue %s\n", new.value);
if ((*sorted).size == 0)
{
new.next = NULL;
new.prev = NULL;
(*sorted).head = &(new);
(*sorted).tail = &(new);
}
else
{
printf("TEST %s\n", (*(*sorted).head).value);
struct Node *current;
current = (*sorted).head;
printf("CURRENT %s\n", (*current).value);
while (strcmp(randomstring,(*current).value) > 0)
{
current = (*current).next;
if (current = NULL)
{
break;
}
}
new.next = current;
if (current != NULL)
{
new.prev = (*current).prev;
if ((*current).prev != NULL)
{
(*(*current).prev).next = &(new);
}
else
{
(*sorted).head = &(new);
}
(*current).prev = &(new);
}
else
{
new.prev = (*sorted).tail;
(*((*sorted).tail)).next = &(new);
(*sorted).tail = &(new);
}
}
(*sorted).size++;
struct Node *printing;
printing = (*sorted).head;
int i;
for (i = 0; i < (*sorted).size - 1; i++)
{
printf("%s -> ", (*printing).value);
printing = (*printing).next;
}
printf("%s\n",(*printing).value);
}

You haven't allocated memory for the value in
strcpy(new.value,randomstring);
you're lucky your subsequent printf works.
You can do for example
new.value = strdup(randomstring);
(don't forget to release memory with free(new.value) when you delete your Node if you do so, because strdup calls malloc).

Er, you're not allocating memory for new either, so when you exit InsertionSort, the Node is dangling.
Should be in InsertionSort
new = (struct Node *)malloc(sizeof(struct Node));
then adjusting everything to use a pointer (that is new -> stuff instead of new.stuff and new instead of &new).
Also in main strings.size in uninitialized
strings.size = 0;
seems missing.
Last one, when you write
if (current = NULL)
I think you mean
if (current == NULL)
(in some C tradition, you'd write if (!current))
With these modifications, it seems to work.

Related

Updating linked-list by pointer inside a function

I'm missing with linked-list and trying to make a function which gonna take of all the odd numbers out of the link and make a new linked-list with them.
The point is that I dont understand how to update the original list by pointer to the function, actually what I made so far is making a new list with the odd numbers but I dont really understand how to "delete" them from the original list and link all the rest togther, then send it back to the main.
Node *build_odd_list(Node *oldlst, Node *newlst) {
Node *temp, *curheadNew;
temp = (Node*)malloc(sizeof(Node));
if (oldlst->value % 2 != 0) {
temp->next = NULL;
temp->value = oldlst->value;
newlst = temp;
curheadNew = newlst;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
while (oldlst) {
if (oldlst->value % 2 != 0) {
temp = (Node*)malloc(sizeof(Node));
temp->value = oldlst->value;
temp->next = NULL;
curheadNew->next = temp;
curheadNew = curheadNew->next;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
}
return newlst;
}
Thanks a lot!
Since you need to return a new list containing the odd numbers, and modify the original list due to removal of the odd numbers, you need to pass two values back to the caller: a pointer to the first element of the updated original list, and a pointer to the first element of the "odd numbers" list.
Since you need to pass the original list to the function anyway, the simplest option for the function is to:
pass a pointer to a pointer to the first element of the original list;
modify the original list via the pointer;
return a pointer to the first element of the "odd numbers" list extracted from the original list.
There is no need to allocate any new elements for the "odd numbers" list as the odd number elements can be moved from one list to the other.
It is worth learning the "pointer to a pointer" trick as it is a common way of manipulating list pointers.
Here is an example program to illustrate the above method. Pay particular attention to the extract_odd_list() function and the call to that function from main().
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int value;
struct _Node *next;
} Node;
/* Move odd numbers in *list to returned list. */
Node *extract_odd_list(Node **list) {
Node *oddstart = NULL; /* start of returned list */
Node **oddend = &oddstart; /* pointer to final link of returned list */
while (*list) {
if ((*list)->value % 2 != 0) {
/* Current element of original *list is odd. */
/* Move original *list element to end of returned list. */
*oddend = *list;
/* Bypass moved element in original list. */
*list = (*list)->next;
/* Update pointer to final link of returned list. */
oddend = &(*oddend)->next;
}
else {
/* Current element of original *list is even. */
/* Skip to next element of original *list. */
list = &(*list)->next;
}
}
/* Terminate the returned list. */
*oddend = NULL;
/* And return it. */
return oddstart;
}
void *printlist(Node *list) {
while (list) {
printf(" %d", list->value);
list = list->next;
}
}
int main(void) {
int i;
Node *list = NULL;
Node *end = NULL;
Node *oddlist;
Node *temp;
/* Construct a list containing odd and even numbers. */
for (i = 1; i <= 10; i++) {
temp = malloc(sizeof(*temp));
temp->value = i;
if (end == NULL) {
list = temp;
}
else {
end->next = temp;
}
end = temp;
}
end->next = NULL;
printf("Original list:");
printlist(list);
printf("\n");
/* Move the "odd number" elements from the original list to a new list. */
oddlist = extract_odd_list(&list);
printf("Updated list:");
printlist(list);
printf("\n");
printf("Odd list:");
printlist(oddlist);
printf("\n");
return 0;
}

Segmentation fault during insertion of node into linked list

I am attempting to alphabetize two separate lists in my add function: one that sorts the nodes by first names, and another that sorts by last names. I also have some logic that checks if a name is already in the list and if it is an error is printed and the list is returned unchanged. Like the title says, I am getting a segmentation fault here and am not sure why. It may be a pretty basic problem but I am new to C and especially new to linked lists.
Here is how the nodes are defined:
typedef struct node {
char *first;
char *last;
long number;
struct node *nextFirst;
struct node *nextLast;
} Node;
typedef struct mlist {
Node *headFirstName;
Node *headLastName;
} MultiLinkedList;
And here is my add function:
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
//make placeholder nodes
Node *a = list->headFirstName;
Node *b = list->headLastName;
// add this new node at the head of the "byFirst" list
if (strcmp(newNode->first, a->first) < 0) {
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
}
for (Node *i = list->headFirstName; i; i = i->nextFirst) {
// add after less alphabetical nodes
if (strcmp(newNode->first, i->first) > 0) {
newNode->nextFirst = i->nextFirst;
i->nextFirst = newNode;
}
// return error for duplicate name
if (strcmp(newNode->first, i->first) == 0 && strcmp(newNode->last, i->last) == 0) {
printf("That person is already in the list! Please try with a different name.\n");
}
}
// add this new node at the head of the "byLast" list
if (strcmp(newNode->last, b->last) < 0) {
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
}
for (Node *j = list->headLastName; j; j = j->nextLast) {
// add after less alphabetical nodes
if (strcmp(newNode->last, j->last) > 0) {
newNode->nextLast = j->nextLast;
j->nextLast = newNode;
}
}
// return the multi-list object with updated or original head pointers
return list;
}
I figured out what my problem was. I had to add return list; to the end of each if statement otherwise the function attempts to perform every true statement; which causes the seg fault. In hindsight I'm surprised I didn't figure this out sooner.

Linked List insertion in Beginning

I am trying basic creation of linked list using C. I have written the following code which is working up until first node but fails eventually on second one. I think the issue is where I am trying to display the node values in list separated by arrow(->). I think my logic is right but please correct me. Thanks in advance
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct node
{
int number;
struct node *next;
};
typedef struct node NODE;
NODE *node1, *node2, *start, *save;
int main()
{
node1 = (NODE *)malloc(sizeof(NODE));
int i = 0;
start = NULL;
for(i = 0; i < 3; i++)
{
int inf;
printf("Enter node value:");
scanf("%d", &inf);
node1->number = inf;
node1->next = NULL;
if(start == NULL)
{
start = node1;
save = node1;
}
else
{
// save=start;
// start=node1;
// node1->next=save;
node1->next = start;
start = node1;
}
while(node1 != NULL)
{
printf("%d ->",node1->number);
node1 = node1->next;
}
}
return 0;
}
The issues are
How you're allocating your nodes for insertion (i.e. save for one, you're not).
How they're placed in the list once you fix the above.
Don't cast malloc in C programs (read here for why).
Fail to check the success of your scanf invoke.
Fail to check the success of your malloc invoke
Before you get discouraged, things you did correctly:
Did not mask a node pointer in a typedef
Properly included a MCVE for review
Prospected the things you may be doing wrong.
A very simple example of iterating three values into a linked list would look something like this:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int number;
struct node *next;
};
typedef struct node NODE;
int main()
{
NODE *head = NULL, *p;
int i = 0;
for(i = 0; i < 3; i++)
{
int inf;
printf("Enter node value:");
if (scanf("%d", &inf) == 1)
{
p = malloc(sizeof *p);
if (p != NULL)
{
p->number = inf;
p->next = head;
head = p;
}
else
{
perror("Failed to allocate new node");
return EXIT_FAILURE;
}
}
else
{
// failed to read data. break
break;
}
// report current linked list
printf("%d", p->number);
for (p=p->next; p; p = p->next)
printf(" -> %d", p->number);
fputc('\n', stdout);
}
// cleanup the linked list
while (head)
{
p = head;
head = head->next;
free(p);
}
head = NULL;
return 0;
}
Input
The values 1 2 3 are input upon being prompted:
Output
Enter node value:1
1
Enter node value:2
2 -> 1
Enter node value:3
3 -> 2 -> 1
Best of luck.
You should use malloc() inside for loop.
Since it is outside, same memory is being used.
As said by Vamsi, you should use malloc to put the nodes on the heap. You also generally shouldn't cast the output of malloc, it isn't needed. And then you could play around with making a doubly-linked list, where you also have a prev pointer inside your struct.

doublepointed list C

I wanted to make a list using double pointer and using void as return.
#include<stdio.h>
#include<stdlib.h>
typedef struct list{
int value;
struct list *next;
}*list;
void addnode(struct list **List, int number) {
if(*List == NULL) {
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
} else {
while((*List)->next != NULL) {
(*List) = (*List)->next;
}
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
}
}
int main() {
list List1 = NULL;
addnode(&List1, 20);
printf("%d \n", List1->value);
addnode(&List1, 30);
printf("%d \n", List1->value);
printf("%d \n", List1->next->value);
return 0;
}
The first if in addnode is always executed but i want to append the list if its not empty but it seems like it never work. Ill also get segmenation fault because in the last printf it tries to take the next element in the list but its never initialized like i want.
If everthing worked as i wanted i should have printed out
printf("%d\n", List1->value)
20
printf("%d\n", List1->value)
20
printf("%d\n", List1->next->value)
30
The size you are passing to malloc is wrong.
You are allocating a struct list, not a struct list *.
If you are trying to append a new list item, remember (*List)->next will already be NULL on the second call. The malloc following that uses the pointer before the NULL list item (*List) when it should be assigned to the next list item, the one that is NULL, to make it non-NULL ((*List)->next=malloc(struct list);).
Also, your malloc should be using sizeof(struct list), without the *. If you add the *, you're allocating a struct list **. A rule you can use is use one * fewer than the destination type as the sizeof operand. Since your destination is *List, which is of type struct list *, use sizeof(struct list). Alternatively, because your destination is *List, use sizeof **List (use one more * than the destination variable has). This avoids you needing to know the type. It won't matter if List or *List is NULL because the sizeof operation is executed first; pointer dereferencing never occurs since sizeof works on the type of the variable.
Modify your program like this
int addNode(struct list **List, int number)
{
struct list *new, *tmp; // new = create new node, tmp = navigate to last
new = malloc(sizeof(struct list));
if(!new) { //always validate "malloc"
perror("malloc");
exit(1);
}
new -> value = value; // assigning values to new node
new -> next = NULL;
if(!(*list)) { //Check if list is empty or not, plz initialize *list#main() with NULL as like your program. or write seperate function to initialize
*list = new;
return 0; //no need write else condition, bcoz its the first node. and u can directly return
}
tmp = *list;
while(tmp -> next) // To navigate to last node
tmp = tmp -> next;
tmp -> next = new; //creating link to new node
return 0;
}
It's better to write print function seperatly.
int print(struct list **list)
{
struct *current; //current is your current node position
current = *list;
while(current) { //loop till current node addr == NULL
printf("%d\t", current -> value);
current = current -> next;
}
printf("\n");
return 0;
}

Linked list in C, is the list being constructed correctly?

I'm trying to implement a linked list abstraction, however I am running into problems. Once I create the linked list and add elements to it. When I print the list it only prints the first element in it in an infinite loop fashion, meaning that either the first element is linked to itself or the print function is incorrect. However, I can't find the problem, could someone help?
The following is the list abstraction:
typedef struct _friend {
char *firstname;
char *lastname;
char birthdate[9];
} friend;
typedef struct _node {
friend *value;
struct _node *next;
} node;
typedef struct _linkedlist {
node *head;
} linkedlist;
The program must follow this abstraction, as it is part of something bigger.
The following are the functions that should print the list and add a node to the beginning of the list:
/* addHead
*
* This function takes two parameters - a linked list and a friend.
* This creates a node for the linked list and connects the friend to the
* node. Then it adds the node to the head of the linked list.
*/
void addHead(linkedlist *llist, friend *f)
{
// create a node and put the friend in it
node *n = (node *)malloc(sizeof(node));
n->value = f;
n->next = NULL;
// if the list is empty
if (llist == NULL)
{
// this link is the entire list
llist->head = n;
printf("adding friend to null list\n");
}
// if the list is not empty
else
{
// make the new link's next pointer point to
// the first link in the list
n->next = llist->head;
printf("adding %s to head\n", n->value->firstname);
// make the head pointer point to the new link
llist->head = n;
}
}
/*
* printList
*
* This steps down through each of the nodes in a linked list and
* prints out the information stored in the friend to which the node points.
* Instead of automatically printing to the screen, it prints to the
* file pointer passed in. If the programmer wants to print to the screen,
* he/she will pass in stdout.
*/
void printList(linkedlist *llist,FILE *fp)
{
node *n;
friend *f;
// for each node, print out the friend attached to it
for(n = llist->head; n != NULL ; n = llist->head->next)
{
// assign f to the friend of the right node
f = n->value;
// print the friend out
fprintf(fp,"%s %s: %s\n",
f->firstname, f->lastname, f->birthdate);
}
}
Thank You
The for loop in printList isn't quite right:
for(n = llist->head; n != NULL ; n = llist->head->next)
This should read:
for(n = llist->head; n != NULL ; n = n->next)
Otherwise from the second iteration onwards, n gets set to the same value every single time.
The following isn't related to the problem you're having, but I thought I'd mention it anyway. In the following code:
if (llist == NULL)
{
// this link is the entire list
llist->head = n;
printf("adding friend to null list\n");
}
if llist == NULL, the llist->head = n will segfault.
With the current signature of addHead(), there's not a lot you can do if llist is NULL (other than printing an error message and bailing out).
If instead you meant to check whether llist->head is NULL, you don't need to do that since the else block already handles that correctly.
Try:
void printList(linkedlist *llist,FILE *fp)
{
node *n;
friend *f;
// for each node, print out the friend attached to it
for(n = llist->head; n != NULL ; n = n->next)
{
// assign f to the friend of the right node
f = n->value;
// print the friend out
fprintf(fp,"%s %s: %s\n",
f->firstname, f->lastname, f->birthdate);
}
}
I have done the following to your program:
slightly modified the friend structure. Declared firstname and lastname as arrays for convenience.
Wrote a main() which calls other functions
error checking in addHead()
added create_friend() function which creates friend struct
added freeList() to release the memory which was malloc()'ed
corrected looping error in your print function
So here it goes..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _friend {
char firstname[10];
char lastname[10];
char birthdate[9];
} friend;
typedef struct _node {
friend *value;
struct _node *next;
} node;
typedef struct _linkedlist {
node *head;
} linkedlist;
void addHead(linkedlist *llist, friend *f)
{
node *n = NULL;
if (( n = (node *)malloc(sizeof(node))) == NULL) {
printf("unable to allocate memory \n");
exit(1);
}
n->value = f;
n->next = NULL;
if (llist == NULL) {
llist->head = n;
printf("adding friend to null list\n");
} else {
n->next = llist->head;
printf("adding %s to head\n", n->value->firstname);
llist->head = n;
}
return;
}
void printList(linkedlist *llist)
{
node *n;
friend *f;
if (llist->head == NULL) {
printf("Empty list \n");
return;
}
for(n = llist->head; n != NULL ; n = n->next) {
f = n->value;
printf("%s %s %d \n", f->firstname, f->lastname, f->birthdate);
}
return;
}
friend * create_friend(char *fn, char *ln, char *dob)
{
friend *fp = NULL;
if ((fp = malloc(sizeof(friend))) == NULL) {
printf("unable to allocate memory \n");
exit(1);
}
strcpy(fp->firstname, fn);
strcpy(fp->lastname, ln);
strcpy(fp->birthdate, dob);
return fp;
}
void freeList(linkedlist *llist)
{
node *cur = llist->head;
node *prev = cur;
friend *f;
while (cur != NULL) {
prev = cur;
cur = cur->next;
f = prev->value;
printf("freeing .. %s %s %d \n", f->firstname, f->lastname, f->birthdate);
free(prev->value);
free(prev);
}
return;
}
int main(void)
{
linkedlist ll;
friend *f;
ll.head = NULL;
f = create_friend("firstname1", "lastname1", "12345678");
addHead(&ll, f);
f = create_friend("firstname2", "lastname2", "12345678");
addHead(&ll, f);
f = create_friend("firstname3", "lastname3", "12345678");
addHead(&ll, f);
printList(&ll);
freeList(&ll);
ll.head = NULL;
printList(&ll);
return 0;
}
Hope this helps!
Should be n = n ->next otherwise you're just getting the next of the head every time.

Resources