Trouble in insertion of string in linked list - c

I am writing a program to insert data to linked list and print it.
LinkedList.c
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
struct node
{
char *data;
struct node *next;
};
void insert(struct node** head_ref,char *new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
struct node *last = *head_ref;
strcpy(new_node->data,new_data);
new_node->next = NULL;
if (*head_ref == NULL)
{
*head_ref = new_node;//assigning head node
return;
}
while (last->next != NULL)
last = last->next;//this helps to traverse to last node
last->next = new_node;
return;
}
void printList(struct node *node)//function to print the linked list
{
while (node != NULL)
{
printf(" %s ", node->data);
node = node->next;
}
}
int main() {
int t;
char datas[1000];
scanf("%d",&t);
struct node* head=NULL;
int i;
for(i=0;i<t;i++)
{
scanf("%s",datas);//this data should be added into the linkedlist
insert(&head,datas);
}
printList(head);
return 0;
}
This program works well for integer but if i use character string instead it showing that there is no response on stdout
I have been trying to debug the code for more hours.

Your code gives undefined behavior.
Have a look at the documentation of strcpy().
Long story short, strcpy() requires the destination (your new_node->data) to be an allocated char array, but you have not allocated the data for it, and you are writing to an undefined (and unallocated) memory.
To overcome it, either allocate space dynamically for the new string (and don't forget to free it when a node is released), or make data a char[] instead of a char*.
In addition, just remember buffer overflow weakness. Since it seems like educational purpose code, just think about it - don't try to solve it, IMO.

You have missed memory allocation, try this:
void insert(struct node** head_ref,char *new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
struct node *last = *head_ref;
// you should allocate memory because you use data as char *
new_node->data = malloc(strlen(new_data)+1);
/* you can use new_node->data = strdup(new_data);
instead of new_node->data = malloc(strlen(new_data)); and strcpy(new_node->data,new_data);
because strdup allocate and copy string with exact size */
strcpy(new_node->data,new_data);
new_node->next = NULL;
if (*head_ref == NULL)
{
*head_ref = new_node;//assigning head node
return;
}
while (last->next != NULL)
last = last->next;//this helps to traverse to last node
last->next = new_node;
return;
}

Related

Deleting a node appended at the end of a linked list in C

I have a linked list where each node stores a word and a number. I can add nodes at the top of the list (push), at the center of the list (insertAfter) and at the end of the list (append). I now added a function to delete nodes, where it will take a char, it will search that char through the list and delete the node that stores that char.
The problem is that deleteNode will work with a normal node added at the top of the list, but when i append a node at the end or add it at the middle of the list it won't work.
Tl;dr deleteNode works with nodes created with push but not with nodes created with append or insertAfter.
The error i get is segmentation fault, so i don't have a specific error from the compiler. I'm trying to debug it by running different parts of the code but i still can't find the problem.
struct Node
{
int data;
char *word;
struct Node *next;
};
void push(struct Node** head_ref, int new_data, char *new_word)
{
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->word= malloc(strlen(new_word));
strcpy(new_node->word, new_word);
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
/* Given a node prev_node, insert a new node after the given
prev_node */
void insertAfter(struct Node* prev_node, int new_data, char *new_word)
{
if (prev_node == NULL)
{
printf("the given previous node cannot be NULL");
return;
}
struct Node* new_node =(struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->word= malloc(strlen(new_word));
strcpy(new_node->word, new_word);
new_node->next = prev_node->next;
prev_node->next = new_node;
}
void append(struct Node** head_ref, int new_data, char *new_word)
{
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref;
new_node->data = new_data;
new_node->word= malloc(strlen(new_word));
strcpy(new_node->word, new_word);
new_node->next = NULL;
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
while (last->next != NULL)
last = last->next;
last->next = new_node;
return;
}
void deleteNode(struct Node **head_ref, char *word)
{
struct Node* temp = *head_ref, *prev;
if (strcmp(word, (*head_ref)->word)==0)
{
*head_ref = temp->next; // Changed head
free(temp); // free old head
return;
}
while (strcmp(word, (*head_ref)->word)!=0)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp); // Free memory
}
This part looks strange:
while (strcmp(word, (*head_ref)->word)!=0)
{
prev = temp;
temp = temp->next;
}
In the strcmp you use head_ref but in the body you update temp to move to the next element.
Did you intend to do:
while (strcmp(word, temp->word)!=0)
{
prev = temp;
temp = temp->next;
}
Further there should probably some check for temp being NULL. Like:
while (temp && strcmp(word, temp->word)!=0)
Apart from what was stated by #4386427, you are not allocating enough space for your strings there:
new_node->word= malloc(strlen(new_word));
Notice that the C library function size_t strlen(const char *str) computes the length of the string str up to, but not including the terminating null character. So i would rather suggest:
new_node->word= malloc(strlen(new_word) + 1);
new_node->word[strlen(new_word)] = '\0';
This can cause you some problems with the memory. ;)
Or event better, use calloc, so the second line will be unnecessary:
new_node->word= calloc(strlen(new_word) + 1, sizeof(char));
The answers you have are OK, but just for the record, after enough practice it should look kinda like this:
void deleteNode(struct Node **pplist, char *word)
{
for (struct Node *n = *pplist; n; n=*(pplist = &(n->next)))
{
if (!strcmp(n->word,word))
{
*ppnode = n->next;
free(n->word);
free(n);
break;
}
}
}
The point is that you can just move the pointer to the node pointer through the list instead of treating the head as a special case.
Similarly, you can do append like this:
void append(struct Node** pplist, int new_data, char *new_word)
{
for(; *pplist; pplist=&((*pplist)->next));
push(pplist, new_data, new_word);
}
and insert_after(prev... is just push(&(prev->next)...

linked list displays extra zero item

I am creating a list with 3 elements but when I print the list , it shows an extra zero element.I can't figure where this comes from.
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
int data;
struct node *next;
} node;
void Push(struct node **head, int data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node));
newNode-> data = data;
newNode-> next = *head;
*head = newNode;
}
void createList(struct node **head)
{
Push(head, 1);
Push(head, 2);
Push(head, 3);
}
void printList(struct node *head)
{
struct node *ptr = head;
while(ptr != NULL)
{
printf("%d \n", ptr-> data);
ptr = ptr-> next;
}
return;
}
int main() {
struct node *head = NULL;
head = (struct node*) malloc(sizeof(struct node));
createList(&head);
printList(head);
printf("\n");
return 0;
}
Output:
3
2
1
0
It's actually displaying an indeterminate value. Because right here:
head = (struct node*) malloc(sizeof(struct node));
Is where you create the first real node, which everything is inserted before. You are (un)lucky the run-time is zeroing out the memory for you. Because that's the only thing stopping you from accessing some random address. In general, the content of the memory returned from malloc is indeterminate.
Remove that line and you'll see only the items added by createList. Plus your program will be with well defined behavior.
You have four nodes in your list: the original that you malloc in "main()” plus the three added via "Push" in "createList". Presumably the data in the extra one is zero because you haven’t set it in main (although I’d expect it to be gibberish since it’s allocated memory but not cleared).

linked list of strings in C

I am trying to create a linked list of strings in C and have had problems adding the first Node into the list. For whatever reason my program prints NULL even though I reference the head variable to newNode but it does not copy the string from struct pointer to struct pointer. Any help is appreciated. Thanks!
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
typedef struct stringData {
char *s;
struct stringData *next;
} Node;
Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}
void insert(Node *head, Node *newNode) {
if (head == NULL) {
head->s = newNode->s;
head = newNode;
}
}
void printList(Node *head) {
while (head != NULL) {
printf("%s\n", head->s);
head = head->next;
}
}
int main()
{
Node *head = createNode(NULL);
Node *a = createNode("A");
insert(head, a);
printList(head);
return 0;
}
Following code snippet is wrong:
void insert(Node *head, Node *newNode) {...}
...
insert(head, a);
You need to pass the pointer by reference. Currently you are changing local copy (argument).
Fix
Change your insert as:
void insert(Node **head, Node *newNode) {...}
And call as:
insert(&head, a);
What elseAtleast insert (and possibly) more functions are not fool-proof (guaranteed null pointer dereference, else case not handled etc). You need to debug and fix many such cases. Working your approach properly on paper before coding may help.
Here is a modified version of the code that gives an example of inserting new nodes at both the start of a list and the end of a list. In fact, the insert function could be used to insert a new node at any position in the list, since all it needs is a pointer to a link and a pointer to the node to be inserted.
#include <stdlib.h>
#include <stdio.h>
typedef struct stringData {
char *s;
struct stringData *next;
} Node;
Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}
void insert(Node **link, Node *newNode) {
newNode->next = *link;
*link = newNode;
}
void printList(Node *head) {
while (head != NULL) {
printf("%s\n", head->s);
head = head->next;
}
}
int main(void)
{
Node *head = NULL;
Node *tail = NULL;
Node *n;
n = createNode("B");
// First node at start of list - head is updated.
insert(&head, n);
// First node is also the tail.
tail = n;
n = createNode("A");
// Insert node at start of list - head is updated.
insert(&head, n);
n = createNode("C");
// Insert node at end of list.
insert(&tail->next, n);
// Update tail.
tail = n;
printList(head);
return 0;
}

insertion doesn't take place for bigger size strings

Below programme doesn’t work for bigger size strings , but it works properly for small strings.I am not sure why sortedInsert function is not taking full length of string.There is no string length constraint also being used in this programme.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* Link list node */
struct node
{
char* pattern;
struct node* next;
};
/* function to insert a new_node in a list. Note that this
* function expects a pointer to head_ref as this can modify the
* head of the input linked list (similar to push())*/
void sortedInsert(struct node** head_ref, struct node* new_node)
{
struct node* current;
/* Special case for the head end */
if (*head_ref == NULL || (strcmp((*head_ref)->pattern ,new_node->pattern)> 0))
{
new_node->next = *head_ref;
*head_ref = new_node;
}
else
{
/* Locate the node before the point of insertion */
current = *head_ref;
while (current->next!=NULL &&
strcmp(current->next->pattern, new_node->pattern)< 0)
{
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
}
}
/* BELOW FUNCTIONS ARE JUST UTILITY TO TEST sortedInsert */
/* A utility function to create a new node */
struct node *newNode( char * pattern)
{
/* allocate node */
struct node* new_node =
(struct node*) malloc(sizeof(struct node));
new_node->pattern = (char *)malloc(sizeof(pattern));
/* put in the data */
strcpy(new_node->pattern , pattern);
new_node->next = NULL;
return new_node;
}
/* Function to print linked list */
void printList(struct node *head)
{
struct node *temp = head;
while(temp != NULL)
{
printf("\n%s", temp->pattern);
temp = temp->next;
}
}
/* Drier program to test count function*/
int main()
{
/* Start with the empty list */
struct node* head = NULL;
struct node* new_node = newNode("a.b.c.d.e.f.g.h.h.j.k.l.m.n.o");
sortedInsert(&head, new_node);
new_node = newNode("a.b.c.de.f.g.h.j.k.l.m.t.y.u.k");
sortedInsert(&head, new_node);
new_node = newNode("a.b.c.d.ef.g.h.h.k.j.l.y.u.l.p");
sortedInsert(&head, new_node);
printf("\n Created Linked List\n");
printList(head);
return 0;
}
Here is the output of above programme, where unexpected output can be seen.
Output:
Created Linked List
a.b.c.d.e.f.)
a.b.c.d.ef.g.h.h.k.j.l.y.u.l.p
a.b.c.de.f.g)
malloc(sizeof(pattern))
and then
strcpy(new_node->pattern , pattern); not correct.
better, use strlen() to get the received string length, then allocate memory, then perform strcpy() or memcpy() to copy the recived string.
Try with below code , it will work. you must pass string length instead of string itself
new_node->pattern = (char *)malloc(strlen(pattern)+1);
/* put in the data */
memcpy(new_node->pattern , pattern,strlen(pattern)+1);
Other answers are correct; however, there seems to be a dedicated function strdup to do what you want:
// Incorrect code
new_node->pattern = (char *)malloc(sizeof(pattern));
strcpy(new_node->pattern , pattern);
// Correct code, provided by user2083356
new_node->pattern = (char *)malloc(strlen(pattern)+1);
memcpy(new_node->pattern , pattern,strlen(pattern)+1);
// Does the same; seems easier to type and understand; also handles errors
new_node->pattern = strdup(pattern);

C: Correctly using malloc for linked list

I am a beginner to C and have a question about the proper use of malloc/free for pointers, particularly in linked lists. I have implemented a method to add a new node to my linked list. The node "head" is a global variable. After creating a new node, I insert it at the front of my list and reassign head to point to it. Here is the code:
int add_entry(char* first_name, char* last_name, char* address, char* telephone)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
strcpy(new_node->m_first_name, first_name);
strcpy(new_node->m_last_name, last_name);
strcpy(new_node->m_address, address);
strcpy(new_node->m_telephone, telephone);
if (num_nodes == 0)
head = new_node;
else {
new_node->m_next = head;
head = new_node;
}
num_nodes++;
return 1;
}
We were told in class that anytime we use malloc, we should also use free. However, in this case use of free for new_node at the end of the program leads to a segmentation fault. What is the proper way to free memory in this case? Thanks!
void free_list(struct node *head)
{
struct node *temp;
while (head) {
free(head->m_first_name);
free(head->m_last_name);
free(head->m_address);
free(head->m_telephone);
temp = head;
head = head->m_next;
free(temp);
}
}
way to free your list:
void freeList(struct node* head)
{
struct node* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}

Resources