I am trying to read from a list that has 1 word per line and 20 lines, and then add each word to the end of a linked list. My problem is that when I print out the linked list at the end it is printing that last word in the file 20 times instead of each word once. I have been working on this for hours and can't figure out what i'm doing wrong.
In my main I have
while (!feof(input)) {
fscanf(input, "%s", currentName);
head = insert(head, currentName);
}
print(head);
delete(head);
Insert Function
node* insert(node* head, char* name) {
node *temp = NULL;
if (head == NULL) {
head = create_node(name);
}
else {
temp = head;
while(temp->next != NULL){
temp = temp->next;
}
temp->next = create_node(name);
}
return head;
}
Create Function
node* create_node(char* name) {
node *newNode;
newNode = malloc(sizeof(node));
if(newNode == NULL) {
printf("Failed to create node");
}
newNode->name = name;
newNode->next = NULL;
return newNode;
}
Print and Delete
void print(node* head){
while (head != NULL) {
printf("%s -> ", head->name);
head = head->next;
}
printf("NULL\n");
}
void delete(node* head) {
node *temp = NULL;
while(head != NULL) {
temp = head;
head = head->next;
free(temp);
}
}
You're saving the address of the same buffer back in main() for each and every insertion. Each node is simply holding the base address of currentName, the content of which is changed with each input processed. Therefore you have a linked list of structures containing name pointers, where each points to the same buffer (currentName). Thus the last one will be the only one you see.
You need to dynamically allocate space for the name in create_node. The following uses the POSIX function strdup() to do this, though you're perfectly free to use a strlen/malloc combination if you desire.
node* create_node(char* name)
{
node *newNode;
newNode = malloc(sizeof(node));
if(newNode == NULL)
printf("Failed to create node");
newNode->name = strdup(name);
newNode->next = NULL;
return newNode;
}
Don't forget when you're cleanup up your linked list to free() each node name to avoid a memory leak.
void delete(node* head)
{
node *temp = NULL;
while(head != NULL)
{
temp = head;
head = head->next;
free(temp->name);
free(temp);
}
}
Unrelated: Your while-loop condition for loading your content is wrong. Read this answer to see why
Related
When I run the program it works except when I delete a fairly large number such as 100 or above, whenever I input anything remotely as large as that number I get the Heap use after free error. The terminal is saying it is caused by line 53 in insert() which is this line, tail->next = newNode;. I know keeping head and tail pointers as global variables are not the best way to write it, but I will change it once I get this to work.
void insert(int nData) {
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node)+10);
newNode->data = nData;
newNode->next = NULL;
if(checkDuplicates(nData)==1){
return;
}else{
if(head == NULL){
head = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
}
}
void delete(int n){
if(head -> data==n){
struct Node *tempHead = head;
head= head -> next;
free(tempHead);
return;
} else{
struct Node *current = head;
struct Node *prev = NULL;
while(current!=NULL&¤t->data!=n){
prev = current;
current = current -> next;
}
if(current==NULL) return;
prev->next = current->next;
free(current);
}
}
There is a possible case where tail->next = newNode would be executed on a freed node: that happens when earlier on you called delete and that deleted the tail node in the list. In that case your code does not adjust the value of tail.
So in delete change:
head = head -> next;
to:
head = head -> next;
if (head == NULL) {
tail == NULL;
}
And in the else block change:
prev->next = current->next;
free(current);
to:
prev->next = current->next;
if (tail == current) {
tail = prev;
}
free(current);
For starters the function insert can produce a memory leak because at first a memory is allocated
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node)+10);
(moreover it is unclear what the magic number 10 means in this expression sizeof(struct Node)+10). And then if the condition of the if statement
if(checkDuplicates(nData)==1){
return;
evaluates to logical true the function exits without freeing the allocated memory.
You need at first to check whether the value is not already present in the list and only after that to allocate memory for the new node.
As for the reason of the error then it seems the reason of the error is inside the function delete. The function does not reset the pointer tail when a single node is present in the list or when the node pointed to by the pointer tail is removed.
And apart from this even the first statement of the function
if(head -> data==n){
can invoke undefined behavior when the function is called for an empty list.
The function should be defined the following way
int delete( int n )
{
struct Node *current = head;
struct Node *prev = NULL;
while ( current != NULL && current->data != n )
{
prev = current;
current = current->next;
}
int success = current != NULL;
if ( success )
{
if ( prev == NULL )
{
head = head->next;
if ( head == NULL ) tail = NULL;
}
else
{
prev->next = current->next;
if ( prev->next == NULL ) tail = prev;
}
free( current );
}
return success;
}
I'm beginner in C and data structures, and getting a frustrating exception. I've compared with other doubly linked list codes but couldn't find the mistake.
While debuging the code, I get a warning about a read access violation from stdio.h and this is the troubled part:
return __stdio_common_vfprintf(_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList);
Could you help me please?
struct Node* NewNode() {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node*));
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
void InsertElement(char con, char name[51]) {
struct Node* new_node = NewNode();
strcpy(new_node->name,name);
if (head == NULL) {
head = new_node;
tail = head;
return;
}
if (con == 'H') {
head->prev = new_node;
new_node->next = head;
head = new_node;
}
else if (con == 'T') {
tail->next = new_node;
new_node->prev = tail;
tail = new_node;
}
}
void DisplayForward() {
if (head == NULL) {
printf("No Songs To Print\n*****\n");
return;
}
struct Node *temp = head;
while (temp != NULL) {
printf("%s\n", temp->name);
temp = temp->next;
}
printf("*****\n");
}
void DisplayReversed() {
if (head == NULL) {
printf("No Songs To Print\n*****\n");
return;
}
struct Node *temp = tail;
while (temp != NULL) {
printf("%s\n", temp->name);
temp = temp->prev;
}
printf("*****\n");
}
It seems the reason of the problem is the specified incorrect size of allocated memory in this declaration
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node*));
^^^^^^^^^^^^
You have to write
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
^^^^^^^^^^^^
That is you need to allocate memory for an object of the type struct Node instead of allocating memory for a pointer of the type struct Node *.
Pay attention to that the function InsertElement is unsafe because the user can specify a wrong value for the parameter con. In this case the function will produce a memory leak because the allocated node will not be inserted in the list and the address of the allocated memory for the node will be lost after exiting the function.
It is better to write two functions one of which will append a node to the beginning of the list and other - to the end of the list. In this case the parameter con will not be needed.
I'm trying to add to my linked list only if the item I'm inserting isn't already in the link list but when I try to traverse it and print out all of the items nothing is printing out. I can't seem to see what I'm doing wrong. Any help would be appreciated
// my add function
void add(char *val)
{
printf("%s", val);// val is getting printed so i know its being passed in.
if(head == NULL){
struct node *new_node = (struct node *)malloc(sizeof(struct node));
head = new_node;
head->item = val;
head->next = NULL;
} else{
struct node *current = head;
struct node *newNode = (struct node *) malloc(sizeof(struct node));
if (newNode == NULL) {
exit(-1);
}
newNode->item = val;
newNode->next = NULL;
while (current != NULL) {
current = current->next;
}
current = newNode;
}
}
//my traverse function
void goThroughList() {
struct node *current = head;
while(current != NULL){
printf("%s\n",current->item);
current= current->next;
}
}
add doesn't successfully add anything once head has been assigned. It only updates a local current pointer. You could fix that by changing the code that searches for the tail of the list to
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
If this doesn't help, can you update your question to show how add is being called? (To rule out the possibility that the same char array is being used for multiple calls, leaving all nodes with their item pointers pointed to the same buffer.
Also, there is no code I can see that checks for duplicates. You could implement this inside the branch of add where head already existed by iterating through the list using strcmp to compare each node's item with val.
your add function is incorrect
try this one :
void add(char *val)
{
printf("%s", val);// val is getting printed so i know its being passed in.
if(head == NULL){
struct node *new_node = (struct node *)malloc(sizeof(struct node));
new_node->item = val;
new_node->next = NULL;
head = new_node;
}
else{
struct node *current = head;
while (current->next != NULL) {
if(strcmp(current->item, val) == 0)
return;
current = current->next;
}
struct node *new_node = (struct node *)malloc(sizeof(struct node));
new_node->item = val;
new_node->next = NULL;
current->next = new_node;
}
}
what list does this function go trought ?
void goThroughList() {
struct node *current = head;
while(current != NULL){
printf("%s\n",current->item);
current= current->next;
}
}
try this instead :
void goThroughList(struct node* llist)
{
if(llist)
{
printf("%s" , llist->item);
goThroughList(llist->next);
}
}
The following is a function that is supposed to do three things:
1.Delete all nodes of value N (char key) in a linked list (the values are always single char character.)
2.Return the head of the linked list.
3.All of this must be done recursively.
node* deleteN(node* head, char key)
{
node* prev;
node* cur;
if (head == NULL)
return NULL;
prev = head;
cur = head->next;
if (head->data == key && head->next != NULL)
{
node* temp = head;
head = temp->next;
free(temp);
}
if (cur->data == key && cur->next == NULL)
{
free(cur);
prev->next = NULL;
}
head->next = deleteN(head->next, key);
return head;
}
My problem is I can delete the nodes just fine and as you can see I have a special case if the node is the final node in the list. However, when I return head, head is pointing to nothing and causes crashes when I try to do other things with the linked list.
My question is: How can I get head to point to the front of the linked list (where it started) at the end of the function after deleting all nodes of value N, and return this pointer?
Simply rebuild the list from the recursion:
node* deleteN(node* head, char key)
{
if (head == NULL)
return NULL;
node* tail = deleteN(head->next, key);
if (head->data == key) {
free(head);
return tail;
} else {
head->next = tail;
return head;
}
}
The title is pretty self explanatory. Here's the function I've written for this purpose:
void wipeLoneCells()
{
cell *tmp;
tail = head;
while (1)
{
if (head == tail && !tail->flag)
{
head = head->next;
free(tail);
tail = head;
continue;
}
tmp = tail->next;
/***/ if (tmp->next == NULL && !tmp->flag)
{
tail->next = NULL;
free(tmp);
break;
}
else if (!tmp->flag)
{
tail->next = tmp->next;
free(tmp);
continue;
}
tail = tail->next;
}
}
The list's head and tail are global, and the list is built by the time this function gets called with head pointing to the first node and tail pointing to the last (whose next is NULL). I'm almost certain that my linked list is built correctly as I can print them with no errors. Sometimes this function works perfectly and sometimes it results in an access violation at the line marked with stars. I know it's not completely wrong as I do get the result I want when it doesn't produce an error, although I do get the error frequently so there must be something I'm overlooking. Thank you in advance for any help.
EDIT: Here's the fixed code:
void wipeLoneCells()
{
cell *tmp;
tail = head;
while (1)
{
if (head == tail && !tail->flag)
{
head = head->next;
free(tail);
tail = head;
continue;
}
tmp = tail->next;
if (tmp->next == NULL && !tmp->flag)
{
tail->next = NULL;
free(tmp);
break;
}
else if (tmp->next == NULL)
{
tail = tmp;
break;
}
else if (!tmp->flag)
{
tail->next = tmp->next;
free(tmp);
continue;
}
tail = tail->next;
}
}
What if
tmp = tail->next;
is NULL? The next line attempts to dereference a NULL pointer, which results in undefined behavior - possibly leading to a crash.
You should check for this condition and take appropriate action.
The correct deleteitem() in a singly linked list should be as follows:
You can avoid the recursion and come up with an iterative version (give it a try but let me know if you need help). I wouldn't use a while(1) for this case!
typedef struct node {
int data;
struct node *next;
}NODE;
/*
(1) deleting head
delete element and adjust head pointer
(2) deleting tail
delete element and adjust tail pointer
(3) one element list
if data is the data for the only element
then delete the list and set head and tail
pointers to NULL
(4) all the other cases
traverse through the list and hold the
previous pointer. delete element and adjust
the next pointers.
(5) if not the above cases, then element not
present.. do nothing..
*/
void deleteitem(int data)
{
printf("%s: %d - ", __FUNCTION__, data);
NODE *cur = head;
NODE *prev = cur;
NODE *temp = NULL;
if (head == NULL) {
assert (tail == NULL);
printf("Empty list \n");
return;
}
if (head->data == data) {
temp = head;
// one element list
if (head == tail)
head = tail = NULL;
else
// list has more than one element
head = head->next;
printf("%d \n", temp->data);
free(temp);
deleteitem(data);
return;
}
while (cur != NULL) {
if (cur->data == data) {
if (cur == tail) {
tail = prev;
}
prev->next = cur->next;
printf(" %d deleted\n", cur->data);
free(cur);
assert(tail->next == NULL);
deleteitem(data);
return;
}
prev =cur;
cur = cur->next;
}
printf(" %d not found\n", data);
return;
}