I am writing a program to become familiar with linked lists and when attempting to insert a new link at the end of the list the value is seemingly not stored. I assume it has to do with a local variable not saving to the variable passed into the function.
The function in question:
int insertAtTail(int intBeingAdded, List *userList){
while(userList->next != NULL){
userList = userList->next;
}
List *newLink = (List *)malloc(sizeof(List));
userList->next = newLink;
newLink->next = NULL;
newLink->value = intBeingAdded;
return 1;
}
The entirety of the file:
#include "stdio.h"
#include "stdlib.h"
typedef struct list{
int value;
struct list * next;
} List;
List * initIntegerList(void);
int insertAtHead(int intBeingAdded, List *userList);
int insertAtTail(int intBeingAdded, List *userList);
void printList(List *userList);
int main(void){
List *myList;
myList = initIntegerList();
insertAtHead(2, myList);
insertAtHead(1, myList);
insertAtTail(6, myList);
printList(myList);
freeList(myList);
}
List * initIntegerList(void){
List * listPointer = (List *)malloc(sizeof(List));
if(listPointer != NULL){
listPointer->next = NULL;
return listPointer;
}else{
printf("Memory not available for allocation\n");
return listPointer;
}
}
int insertAtHead(int intBeingAdded, List *userList){
List *previousHead = (List *)malloc(sizeof(List));
if(previousHead != NULL){
previousHead->value = intBeingAdded;
previousHead->next = userList->next;
userList->next = previousHead;
return 1;
}
return 0;
}
int insertAtTail(int intBeingAdded, List *userList){
while(userList->next != NULL){
userList = userList->next;
}
List *newLink = (List *)malloc(sizeof(List));
userList->next = newLink;
newLink->next = NULL;
newLink->value = intBeingAdded;
return 1;
}
void printList(List *userList){
printf("Values in list: ");
List *currentLink = userList;
while(currentLink->next != NULL){
printf(" %d", currentLink->value);
currentLink = currentLink->next;
}
printf("\n");
}
The output I am seeing is only 0,1,2 are stored and the 6 is not making it.
When you print the list:
while(currentLink->next != NULL){
You stop when you reach the last node and don't print its contents. You instead want:
while(currentLink != NULL){
Also, your list has a dummy entry at the start of the list. When you print the list, you want to skip that one.
List *currentLink = userList->next;
Your list is built such a way that the head node does not contain a value. It is a dummy node. On the other hand, the last node always contains the data member next equal to NULL.
So this condition in the function printList
while(currentLink->next != NULL){
does not output the value of the last node.
The function can be written like
void printList( const List *userList )
{
printf("Values in list: ");
if ( userList != NULL )
{
for ( const List *currentLink = userList->next;
currentLink != NULL;
currentLink = currentLink->next )
{
printf( " %d", currentLink->value );
}
}
printf("\n");
}
Pay attention to that it is a bad idea to have a dummy node as a head node. The head node should be just set to NULL.
Related
I encountered a problem during this task. I'm just take list, check that currently processed element is in it. If is skip it, else add to new list.
I wrote three function to do this. One that search particular element, next which is checking for element exist in new list, and the last which is get everything together.
I've tried to do this in two ways:
First checking for occurrence in "old" list, it works, but not at all ( writes to new list in descending order) also I think for particular example it won't work.
Second checking for occurrence of element in currently created list, but this doesn't work.
Here is the code:
struct list *search_node(struct list *prt, char *to_search) {
is_empty();
short is_found = -1;
while (prt != NULL && ((is_found = strcmp(prt->word, to_search) != 0))) {
prt = prt->next;
}
if (!is_found)
return prt;
else
return NULL;
}
bool is_on_list(struct list *ptr, char *str) {
if (search_node(ptr, str) != NULL)
return 1;
else
return 0;
}
struct list *without_repetiton(struct list *head) {
struct list *new_list = NULL;
struct list **new_el = &new_list;
struct list *prt1 = head, *check;
while (prt1 != NULL) {
//printf("test = %s\n", prt1 -> word);
check = new_list;
if (!is_on_list(prt1->next, prt1->word)) { // or (new_list, prt1 -> word)
*new_el = (struct list *)malloc(sizeof(struct list));
memcpy(*new_el, prt1, sizeof(struct list));
new_el = &((*new_el)->next);
}
prt1 = prt1->next;
}
return new_list;
}
There is the structure of list:
struct list {
char *word;
struct list *next;
struct list *prev;
};
I have two questions, first why the first approach writes the list in descending order, and second why when I've tried to search occurrence of word in already created list in not work?
IO samples:
When : is_on_list(prt1->next, prt1->word))
Fist list: One, One, Two
Second list: Two, One
When : is_on_list(new_list, prt1->word))
The first list is the same as second.
Your code does not construct the duplicate list correctly: simplify the code and link the new elements by hand instead of using memcpy():
struct list *search_node(struct list *ptr, const char *to_search) {
while (ptr != NULL) {
if (!strcmp(ptr->word, to_search))
return ptr;
}
return NULL;
}
bool is_on_list(struct list *ptr, const char *str) {
return search_node(ptr, str) != NULL;
}
struct list *without_repetiton(struct list *head) {
struct list *new_list = NULL;
struct list *tail = NULL;
for (struct list *ptr = head; ptr != NULL; ptr = ptr->next) {
if (!is_on_list(new_list, ptr->word)) {
struct list *node = malloc(sizeof(*node));
node->next = NULL;
node->prev = tail;
node->str = strdup(ptr->word);
if (tail == NULL) {
new_list = tail = node;
} else {
tail->next = node;
tail = node;
}
}
}
return new_list;
}
When trying to run my deleteLast() function twice (to get an empty list) on a linked list with two nodes, I am running into a problem. The code compiles and runs, but when I call traverse() on my empty linked list, I get an infinite while loop, and I cannot determine why.
Oddly enough, if I call deleteFirst() twice instead of deleteLast(), the program runs and terminates properly.
Below is the code for my methods:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
struct NODE
{
struct NODE *link;
int value;
};
typedef struct NODE Node;
/* Deletes the first item in the list and returns next item */
Node *deleteFirst(Node **ptrToHeadPtr)
{
Node *current;
// If list is empty do nothing
if (*ptrToHeadPtr == NULL)
return NULL;
else
{
current = *ptrToHeadPtr;
*ptrToHeadPtr = current->link;
free(current);
}
return *ptrToHeadPtr;
}
/* Inserts a new Node to the end of the list and returns it */
Node *insertLast(Node **ptrToHeadPtr, int val)
{
Node *current, *lastNode;
lastNode = (Node *)malloc( sizeof (Node) );
// Check if malloc was successful
if(!lastNode) return NULL;
lastNode->value = val;
lastNode->link = NULL;
if (*ptrToHeadPtr == NULL)
*ptrToHeadPtr = lastNode;
else
{
current = *ptrToHeadPtr;
// Walk to the end of the list
while(current->link != NULL)
current = current->link;
// Insert new item at the end of the list
current->link = lastNode;
}
return lastNode;
}
/* Deletes the last Node in the list and returns*/
Node *deleteLast(Node **ptrToHeadPtr)
{
Node *current, *previous;
/* If list is empty do nothing */
if (*ptrToHeadPtr == NULL)
return NULL;
current = *ptrToHeadPtr;
previous = NULL;
/* If list has one item delete it and return NULL */
if (current->link == NULL)
{
*ptrToHeadPtr == NULL;
free(current);
return NULL;
}
else
{
/* Walk to the end of the list */
while (current->link != NULL)
{
previous = current;
current = current->link;
}
previous->link = NULL;
free(current);
return previous;
}
}
/* Traverses the list, printing the value of each Node */
void traverse(Node*p)
{
while( p!= NULL )
{
printf("%d ",p->value);
p=p -> link;
}
}
/* Walks through the linked list, freeing memory of each Node */
void freeList(Node *p)
{
Node *temp;
while( p != NULL )
{
temp = p;
p = p-> link;
free(temp);
}
}
int main()
{
Node *headPtr = NULL;
insertLast( &headPtr, 33 );
insertLast( &headPtr, 35 );
traverse(headPtr);
printf("\n");
deleteFirst ( &headPtr );
traverse(headPtr);
printf("\n");
deleteLast ( &headPtr );
traverse(headPtr);
freeList(headPtr);
return 1;
}
In your deleteLast() function (They're called functions in C, just so you know, not methods. Not trying to sound snarky.)
/* If list has one item delete it and return NULL */
if (current->link == NULL)
{
*ptrToHeadPtr == NULL; // CHANGE THIS TO =, NOT ==
free(current);
return NULL;
}
edit: Just like the above poster suggested, you should definitely compile with -Wall (the W is case sensitive, must be capitalized.) It would have caught this.
This is my insertion sort function :
Student *sort(Student* node)
{
if (node == NULL || !node->next)
return node;
Student *sorted = NULL;
while (node != NULL)
{
Student *head = node;
Student **tail = &sorted;
node = node->next;
while (!(*tail == NULL || head->id < (*tail)->id))
{
tail = &(*tail)->next;
}
head->next = *tail;
*tail = head;
}
return sorted;
}
So if this is supposed to sort 3.3, 3.1 and 3.8 , it sorts them such as :
3.3
3.8
I don't know what happens to the first element. If I give it a larger set of text to sort, it misses almost half of the text.
Been trying to figure out why it does this. I'm pretty sure it's the problem with my sorting function.
write function. This function is supposed to simply write the sorted result to a file :
void write(Student* node) {
Student * curr = NULL;
curr = node;
FILE *ptr = fopen("student_out.txt", "w");
if (curr == NULL)
{
printf("Nothing to list. \n");
exit(1);
}
int i=0;
while(curr !=NULL) {
fprintf(ptr,"%d, %s, %s, %s, %.2f\n", curr->id, curr->firstname, curr->lastname, curr->major, curr->gpa);
curr = curr -> next;
}
return;
}
Seems to be working, the problem could be with the print out. Example code to test the case mentioned above, converted to be C89 compatible (since I'm using Visual Studio). I would have swapped the names head and node, but I left them as is to match the original example. I also changed the compare to stop when (*tail)->id > head->id (using <= in the compare instead of <) so that the original order of "equal" nodes is preserved.
#include <stdio.h>
typedef struct Student_{
struct Student_ *next;
double id;
}Student;
Student *sort(Student* node)
{
Student *sorted = NULL;
Student **tail;
Student *head;
if (node == NULL || !node->next)
return node;
while (node != NULL)
{
head = node;
node = node->next;
tail = &sorted;
while (*tail != NULL && (*tail)->id <= head->id)
tail = &(*tail)->next;
head->next = *tail;
*tail = head;
}
return sorted;
}
int main()
{
Student a[3] = {{&a[1],3.3},{&a[2],3.1},{NULL,3.8}};
Student *b;
b = sort(a);
while(b){
printf("%3.1lf ", b->id);
b = b->next;
}
printf("\n");
return 0;
}
When I try to delete every other element in the list using the deleteinst method the method does nothing to the linked list and there are no errors. I'm really not sure why it's not working I've seen the same deleteinst method used in a different program. Maybe it has something to do with the pointers. If I run deleteInst(track.prev, &head); without the while loop the list still remains unchanged.
Please let me know if you have any idea or need more info. Thank you for your time.
int main()
{
node *head;
node *track;
head = ReadNodeList(stdin);
track = LastNode(head); //goes to last node.
while(track != NULL){
int i=0;
//delete every other node
if(i%2 == 1){
deleteInst(track, &head);
}
i++;
track = track->prev;
}
}
void deleteInst(Instruction *victim, Instruction **head){
if(*head == NULL || victim == NULL)
return;
if(*head == victim)
*head = victim->next;
if(victim->next != NULL)
victim->next->prev = victim->prev;
if(victim->prev != NULL)
victim->prev->next = victim->next;
free(victim);
return;
}
One immediately obvious glaring problem: you really don't want to do this:
deleteInst(track, &head);
track = track->prev;
The instant you free that node, you lose the right to access its members. Save it first then recover after the delete:
node *save_prev = track->prev;
deleteInst(track, &head);
track = save_prev;
Another thing I'd check is that the list structure is correct, with something like (only during debug):
static void checkList (node *curr) {
int count = 0;
// PreCon: head->prev must be null.
if (curr != NULL) {
if (curr->prev != NULL) {
puts ("Linked list structure error A!");
exit (1);
}
}
// Check all nodes.
while (curr != NULL) {
// PreCon: curr->prev->next must be curr.
if (curr->prev != NULL) {
if (curr->prev->next != curr) {
puts ("Linked list structure error B!");
exit (1);
}
}
// PreCon: curr->next->prev must be curr.
if (curr->next != NULL) {
if (curr->next->prev != curr) {
puts ("Linked list structure error C!");
exit (1);
}
}
// Move to next and keep count.
curr = curr->next;
count++;
}
// All okay, output success message with size.
printf ("Linked list structure okay, size = %d\n", count);
}
Calling that with checkList (head) will validate that your linked list meets all the validity preconditions, on the off-chance that you may have buggy code elsewhere, such as when creating the list in ReadNodeList().
Beyond that, I suggest single stepping the code in your IDE or debugger after ReadNodeList() to see what it's actually doing. And, if you don't have an IDE/debugger, pepper your source code with lots of lines like:
printf ("DEBUG %d: track = %p\n", __LINE__, track);
and then examine the output of the debug statements to analyse the flow through your program.
Now, if you were to actually do that debugging exercise, it may surprise you to find out that deleteInst never appears to be called, because i seems to be always set to 0.
And the fault of that little problem lies here:
while (track != NULL) {
int i = 0; // <<<<<<<
//delete every other node
if (i%2 == 1) {
deleteInst (track, &head);
}
i++;
track = track->prev;
}
Yes, that's right, you are setting i to 0 every single time through the loop, hence i % 2 will never be equal to 1. You need to initialise i before the loop (and with the undefined behaviour of accessing freed memory removed as well):
int i = 0;
while (track != NULL) {
node *save_prev = track->prev;
//delete every other node
if (i%2 == 1)
deleteInst (track, &head);
i++;
track = save_prev;
}
Doubly linked lists are a whole lot easier to work with if you put a tail on the list during the list initialization. This eliminates most of the mind-numbing corner cases.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
struct node *next;
struct node *prev;
int data;
}
node;
void ShowList( node *head );
void AppendNodeWithData( node *tail, int data );
void RemoveNode( node *item );
int main( void )
{
int i;
node *head, *tail, *item, *temp;
// allocate and initialize the doubly linked list
head = malloc( sizeof(node) );
tail = malloc( sizeof(node) );
if ( !head || !tail )
exit( 1 );
head->next = tail;
head->prev = NULL;
tail->next = NULL;
tail->prev = head;
// add some items to the list
for ( i = 0; i < 20; i++ )
AppendNodeWithData( tail, i );
ShowList( head );
// remove every other item
for ( item = tail->prev; item != NULL && item->prev != NULL; item = temp )
{
temp = item->prev->prev;
RemoveNode( item );
}
ShowList( head );
}
void ShowList( node *head )
{
node *item;
for ( item = head->next; item->next != NULL; item = item->next )
printf( " %d", item->data );
printf( "\n" );
}
void AppendNodeWithData( node *tail, int data )
{
node *item;
if ( (item = malloc( sizeof(node) )) == NULL )
exit( 1 );
item->data = data;
item->prev = tail->prev;
item->next = tail;
tail->prev->next = item;
tail->prev = item;
}
void RemoveNode( node *item )
{
item->next->prev = item->prev;
item->prev->next = item->next;
free( item );
}
This code adds only one element to the end of list(just creates head element, nothing after that).What is wrong in my program? Should I pass two items in function, head and item or just one?
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct MyList
{
int x;
int y;
struct MyList * next;
}List;
typedef List * Item;
void AddEnd(Item * head);
void PrintList(Item * head);
int main(void)
{
int response;
Item head;
head = NULL;
while(1)
{
printf("1- Print, 2 - Add to End, 3 - exit\n");
scanf("%d", &response);
switch(response)
{
case 1: PrintList(&head); break;
case 2: AddEnd(&head); break;
case 3: return 0;
}
}
return 0;
}
void PrintList(Item * head)
{
Item temp;
temp = *head;
while(temp != NULL)
{
printf("%d %d\n", temp->x, temp->y);
temp = temp->next;
}
}
void AddEnd(Item * head)
{
Item new, temp;
new = (Item)malloc(sizeof(new));
printf("Enter x and y: ");
scanf("%d %d", &new->x, &new->y);
new->next = NULL;
if(*head == NULL)
{
*head = new;
}
else
{
temp = *head;
while(temp != NULL)
{
temp = temp->next;
}
temp = new;
}
}
This code down that I just tried don't work also:
void AddEnd(Item * head, Item * item)
{
Item new, temp;
new = (Item)malloc(sizeof(new));
printf("Enter x and y: ");
scanf("%d %d", &new->x, &new->y);
new->next = NULL;
if(*head == NULL)
{
*head = new;
}
else
{
temp = *head;
while(temp != NULL)
{
temp = temp->next;
}
temp = new;
*item = temp;
}
}
In your AddEnd function in the else clause, when you exit the while loop, temp is now NULL. However, the element before it is still pointing to NULL.
Try something like
temp = *head;
if (temp->next == NULL) {
temp->next = new;
} else {
while((temp->next) != null) {
temp = temp->next;
}
temp->next = new;
}
in your else clause.
(This, and the apparent issue with your understanding of malloc referenced by the others, new should be a Item * and the malloc call should be malloc(sizeof(Item)). You also don't need to cast the return value of malloc (indeed, there are some pitfalls that happen if you do).) Reading your typedefs a little more closely, new should actually be an Item (since it's a pointer to a List struct and you have typedef List* Item). Try new = malloc(sizeof(List)); and just declare new to be of type List *. (The typedef List * Item makes your code hard to read; it becomes less clear what's a pointer and what isn't.)
You need to change this:
new = (Item)malloc(sizeof(new));
To this:
new = (Item *)malloc(sizeof(List));
Hope this helps