I have written a linked list program which stores data member as void *.
while trying to store annd print using scanf/printf functions, I am getting segmentation fault.
node definition -->
typedef struct node {
struct node *next;
void *data;
}node;
main function -->
head=(node *)malloc(sizeof(node));
if (head==NULL){
printf("error in allocation of memory\n");
exit(EXIT_FAILURE);
}
tail=(node*)create(head);
create function -->
void *create(node *current)
{
int user_choice;
while(current){
printf("\nEnter the data:");
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
current=current->next;
}
else{
current->next=NULL;
}
}
return current;
}
can anyone tell what is the correct argument for scanf & prinf should be..?
working code after incorporating points given in answers...
void *create(node *current)
{
node *temp;
int user_choice;
while(current){
printf("\nEnter the data:");
current->data=(char*)malloc(10*sizeof(char));
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
}
else{
current->next=NULL;
temp=current;
}
current=current->next;
}
return temp;
}
In your code,
scanf("%s",current->data);
is attempt to make use of an unitialized pointer, it invokes undefined behavior.
You need to follow either of bellow approach,
make the pointer point to valid chunk of memory (using malloc() and family for dynamic allocation, for example)
use an array.
You should first initialize data member of structure because
current->data = malloc("passes size here");
For putting data you have to typecast first this data because void is not storage type. void pointer can be used to point to any data type.
Like
*(char *)(current->data) = 1;
As others have said:
scanf("%s",current->data);
Is undefined in C. current->data needs to be pointing somewhere before you can store anything in it.
You should instead:
Accept input from scanf.
Store in temporary buffer.
Insert into linked list
print out whole linked list at the end
free() linked list at the end.
I also feel that your current void *create function is doing too much, and it would be easier to split up your code into different functions, just to make it easier to handle all the pointer operations, inserting etc.
To demonstrate these points, I wrote some code a while ago which does these things, and has been modified to help you with your code. It is not the best code, but it does use these points that will help you with your code.
Here it is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRLEN 100
typedef struct node {
void *data;
struct node *next;
} node_t;
typedef struct {
node_t *head;
node_t *foot;
} list_t;
list_t *create_list(void);
node_t *generate_node(void);
list_t *insert_node(list_t *list, char *data);
void print_list(list_t *list);
void free_list(list_t *list);
int
main(int argc, char *argv[]) {
list_t *list;
char data[MAXSTRLEN];
int user_choice;
list = create_list();
while (1) {
printf("Enter the data: ");
scanf("%s", data);
printf("\nType '1' to continue, '0' to exit:\n");
if (scanf("%d",&user_choice) != 1) {
printf("Invalid input\n");
exit(EXIT_FAILURE);
}
if (user_choice == 1) {
list = insert_node(list, data);
} else {
list = insert_node(list, data);
break;
}
}
print_list(list);
free_list(list);
list = NULL;
return 0;
}
/* inserting at foot, you can insert at the head if you wish. */
list_t
*insert_node(list_t *list, char *data) {
node_t *newnode = generate_node();
newnode->data = malloc(strlen(data)+1);
strcpy(newnode->data, data);
newnode->next = NULL;
if (list->foot == NULL) {
list->head = newnode;
list->foot = newnode;
} else {
list->foot->next = newnode;
list->foot = newnode;
}
return list;
}
node_t
*generate_node(void) {
node_t *new = malloc(sizeof(*new));
new->data = NULL;
return new;
}
void
print_list(list_t *list) {
node_t *curr = list->head;
printf("\nlinked list data:\n");
while(curr != NULL) {
printf("%s\n", (char*)curr->data);
curr = curr->next;
}
}
list_t
*create_list(void) {
list_t *list = malloc(sizeof(*list));
if (list == NULL) {
fprintf(stderr, "%s\n", "Error allocating memory");
exit(EXIT_FAILURE);
}
list->head = NULL;
list->foot = NULL;
return list;
}
void
free_list(list_t *list) {
node_t *curr, *prev;
curr = list->head;
while (curr) {
prev = curr;
curr = curr->next;
free(prev);
}
free(list);
}
UPDATE:
Also note how I allocated memory for newnode->data?
Like this:
newnode->data = malloc(strlen(data)+1); //using buffer from scanf
This now means I can store data in this pointer, your current->data will need to do something similar.
working code-->
void *create(node *current)
{
node *temp;
int user_choice;
while(current){
printf("\nEnter the data:");
current->data=(char*)malloc(10*sizeof(char));
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
}
else{
current->next=NULL;
temp=current;
}
current=current->next;
}
return temp;
}
Please try with this
void *create(node *current)
{
int user_choice;
while(true){
if(current == NULL) {
current = (node *)malloc(sizeof(node));
current->data = NULL;
current->next = NULL;
}
printf("\nEnter the data:");
scanf("%s",current->data);
printf("stored at %p\n", (void *)current->data);
printf("%s",current->data);
//printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
current=current->next;
}
else{
current->next=NULL;
tail = current;
current=current->next;
break;
}
}
return current;
}
Note: The element has to be initialized (ie; it has to be alloted with some memory) before we are trying to make use of it.
Related
I created a standard linked list in C. It asks the user to input a number, and program end if user input #. If the user inputs anything else the program will stop.
The problem is that my program runs forever and prints the normal list at first then keeping print the last element of the linked list.
Hope someone could tell me where did I made mistake.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} NodeT;
void freeLL(NodeT *list) {
NodeT *p, *temp;
p = list;
while (p != NULL) {
temp = p->next;
free(p);
p = temp;
}
}
void showLL(NodeT *list) {
NodeT *temp = list;
temp = temp->next;
printf("Done. The list is ");
printf("%d", temp->data);
temp = temp->next;
//iterate the entire linked list and print the data
while (temp != NULL) {
printf("-->");
printf("%d", temp->data);
temp = temp->next;
}
}
NodeT *joinLL(NodeT *list, int v) {
NodeT *current = list;
NodeT *head;
head->data = v;
head->next = NULL;
while (current->next != NULL) {
current = current->next;
}
current->next = head;
return head;
}
int main() {
int data;
NodeT *list = NULL;
list = (NodeT *)malloc(sizeof(NodeT));
printf("Enter a number: ");
if (scanf("%d", &data) != 1) {
printf("Done. ");
} else {
printf("Enter a number: ");
joinLL(list, data);
while (1 == scanf("%d", &data)) {
printf("Enter a number: ");
joinLL(list, data);
}
showLL(list);
freeLL(list);
}
return 0;
}
I believe the problem is in the joinLL function which add a new node at the end of the linked list.
The problem is you do not allocate elements in joinLL: only a single element in allocated in main().
You should instead always allocate the element in joinLL and update the head pointer from the return value.
Similary, freeLL should take a pointer to head and set it to NULL for consistency.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} NodeT;
void freeLL(NodeT *p) {
while (p != NULL) {
NodeT *temp = p->next;
free(p);
p = temp;
}
}
void showLL(const NodeT *list) {
NodeT *p = list;
printf("The list is ");
if (p == NULL) {
printf("empty");
} else {
printf(" %d", temp->data);
while ((p = p->next) != NULL) {
printf("--> %d", temp->data);
}
}
printf("\n");
}
NodeT *joinLL(NodeT *head, int v) {
NodeT *newp = malloc(sizeof(*p));
NodeT *current;
if (newp == NULL) {
fprintf(stderr, "allocation failure\n");
exit(1);
}
newp->data = v;
newp->next = NULL;
if (head == NULL) {
return newp;
}
for (current = head; current->next != NULL; current = current->next)
continue;
current->next = newp;
return head;
}
int main() {
NodeT *list = NULL;
for (;;) {
int data;
printf("Enter a number: ");
if (scanf("%d", &data) != 1) {
printf("Done. ");
break;
}
list = joinLL(list, data);
}
showLL(list);
freeLL(list);
return 0;
}
Your program keeps running because of a memory access error, you did not allocate memory for your head(you set a pointer, but use it directly without initializing it)
Change to this may solve the problem:
head=(NodeT*)malloc(sizeof(NodeT));
if(NULL==head)
{
// failed : do something...
return NULL;
}
head->data=v;
head->next=NULL;
When I just tested it, I found that there was another problem:
list = (NodeT*)malloc(sizeof(NodeT));
malloc will not be initialize your list, so the value that your list->next initially points to is uncertain.
in c, malloc does not need to be cast.
I have a problem with this code. I have tried to debug with gdb and Valgrind, But nothing works...
The goal of the code is to create a list, where every string is added only if no existing node with the same string in already part of the list.
This is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct node {
char *word;
struct node *next;
};
void print_list(struct node *head) {
while ((head) != NULL) {
printf(" %s -> ", head->word);
head = (head->next);
}
}
// insert a new node in head
void add_n(struct node **head, char *str) {
struct node *new;
new = malloc(sizeof(struct node));
if (new == NULL) {
printf("Not enough memory\n");
exit(EXIT_FAILURE);
}
new->word = str;
new->next = NULL;
if ((*head) == NULL){
(*head) = new;
}
while ((*head)->next != NULL) {
head = &(*head)->next;
}
(*head)->next = new;
}
// check if str is present in the list
int find_string(struct node **head, char *str) {
int found = 0;
while ((*head) != NULL) {
int i = strcmp(str, (*head)->word); //i=0 are the same
if (i == 0) {
found = 1;
return found;
}
head = &((*head)->next);
}
return found;
}
// insert a new string in the list only if is new
void insert(struct node **head, char *str) {
if (find_string(head, str) == 0) {
add_n(head, str);
}
}
void rem_ent(struct node **head, struct node *ent) {
while ((*head) != ent) {
head = &((*head)->next);
}
(*head) = ent->next;
free(ent);
}
void fini_list(struct node **head) {
while ((*head) != NULL) {
rem_ent(head, *head);
head = &((*head)->next);
}
}
int main() {
struct node *head = NULL;
insert(&head, "electric");
print_list(head);
insert(&head, "calcolatori");
print_list(head);
insert(&head, "prova pratica");
print_list(head);
insert(&head, "calcolatori");
print_list(head);
fini_list(&head);
//printf("lunghezza media = %f\n", avg_word_lenght(head));
return 0;
}
Maybe the error might be stupid, but I spent a lot of time debugging without success.
the function fini_list invokes undefined behavior due to the redundant statement
head=&((*head)->next);
because the function rem_ent already set the new value of the pointer head.
void rem_ent(struct node** head, struct node * ent){
while((*head) != ent){
head= &((*head)->next);
}
(*head)= ent->next;
free(ent);
}
Remove the statement
void fini_list(struct node** head){
while((*head) != NULL){
rem_ent(head, *head);
}
}
Also change the function add_n the following way
// insert a new node in head
void add_n(struct node ** head, char* str){
struct node * new;
new = malloc(sizeof(struct node));
if (new == NULL) {
printf("Not enough memory\n");
exit(EXIT_FAILURE);
}
new->word= str;
new->next = NULL;
if ((*head)==NULL){
(*head)=new;
}
else
{
while((*head)->next != NULL){
head = &(*head)->next;}
(*head)->next = new;
}
}
And next time format the code such a way that it would be readable.
In general you should allocate dynamically memory for strings that will be stored in nodes of the list.
So I'm having trouble getting my program to print both the strings I input, or however many you want to put in the list, it always prints out the last string inputted multiple times. I am sorry about all the commented out code, most of it you don't need to read.
#include<stdio.h>
#include<stdlib.h>
struct node{
char *data;
struct node *next;
}*head;
typedef struct node NODE;
// Function prototypes
void append(char myStr[]);
void add( char myStr[] );
//void addafter(char myStr[], int loc);
void insert(char myStr[]);
int delete(char myStr[]);
void display(struct node *r);
int count();
// main function
int main()
{
int i;
struct node *n;
head = NULL;
char myStr[50];
while(1)
{
printf("\nList Operations\n");
printf("===============\n");
printf("1.Insert\n");
printf("2.Display\n");
printf("3.Size\n");
printf("4.Delete\n");
printf("5.Exit\n");
printf("Enter your choice : ");
if(scanf("%d", &i) <= 0)
{
printf("Enter only an Integer\n");
exit(0);
}
else
{
switch(i)
{
case 1:
printf("Enter the name to insert : ");
scanf("%50s", myStr);
insert(myStr);
break;
case 2:
if(head == NULL)
{
printf("List is Empty\n");
}
else
{
printf("Name(s) in the list are : ");
}
display(n);
break;
case 3:
printf("Size of the list is %d\n",count());
break;
case 4:
if(head == NULL)
printf("List is Empty\n");
else
{
printf("Enter the myStrber to delete : ");
scanf("%50s",myStr);
if(delete(myStr))
printf("%s deleted successfully\n",myStr);
else
printf("%s not found in the list\n",myStr);
}
break;
case 5:
return 0;
default:
printf("Invalid option\n");
}
}
}
return 0;
}
// Function definitions
void append(char myStr[])
{
struct node *temp,*right;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = myStr;
right=(struct node *)head;
while(right->next != NULL)
{
right = right->next;
}
right->next = temp;
right = temp;
right->next = NULL;
}
// adding a node to the beginning of the linked list
void add( char myStr[] )
{
struct node *temp;
temp =(struct node *)malloc(sizeof(struct node));
temp->data = myStr;
// only one node on the linked list
if (head == NULL)
{
head = temp;
head->next = NULL;
}
else
{
temp->next = head;
head = temp;
}
}
void insert(char myStr[])
{
int c = 0;
struct node *temp;
temp = head;
if(temp == NULL)
{
add(myStr);
}
else
{
append(myStr);
}
}
int delete(char myStr[])
{
struct node *temp, *prev;
temp = head;
while(temp != NULL)
{
if(temp->data == myStr)
{
if(temp == head)
{
head = temp->next;
head = (*temp).next;
free(temp);
return 1;
}
else
{
prev->next = temp->next;
free(temp);
return 1;
}
}
else
{
prev = temp;
temp = temp->next;
}
}
return 0;
}
void display(struct node *r)
{
r = head;
if(r == NULL)
{
return;
}
while(r != NULL)
{
printf("%s ", r->data);
r = r->next;
if(r == NULL)
{
printf("\nOur linked list is finished!");
}
}
printf("\n");
}
int count()
{
struct node *n;
int c = 0;
n = head;
while(n != NULL)
{
n = n->next;
c++;
}
return c;
}
The problem seems to be that myStr at main function is a char[], so it's content is overritten every time you insert data. Notice that struct node data field is a char*, it's just pointing to myStr address.
Hope this help!
Your program has only one place to write your input, myStr.
With each input, myStr is erased and a something else is written to myStr.
The data member of all of the nodes, points to myStr. myStr will only contain the last input.
The display() function asks each node what is data. data points to myStr so each node prints the contents of myStr. myStr will only contain the last input so all the nodes print the last input.
To fix this, in the add() and append() functions, you need to give the data member some memory by using malloc(). Then copy the contents of myStr to the data member by using strcpy().
temp->data = malloc ( strlen ( myStr) + 1);
strcpy ( temp->data, myStr);
Do this instead of temp->data = myStr;
You will need #include<string.h>
The memory will need to be free()'d in the delete() function.
free(temp->data);
Do this before freeing temp
char *data
that variable from struct is always assigned with the address of myStr as its a pointer it would only show you the value of myStr
So this is my code for the a linked list program. I know it's not that great, but it works. I want to change the ins() function so that new elements are inserted to the list by magnitude.. i.e., the last node on the list will contain the greatest integer, and the smallest the first. The integers are read in from a text file, and as you can see in main(), the INSERT and REMOVE commands in the text file are interpreted as commands to either insert (the following integer on the next line) into the list, or remove an element from the list. How can I do this with my existing code? I tried modifying my ins() function, but was unable to get my list ordered properly.
#include <stdio.h>
#include <stdlib.h>
struct node {
int number;
struct node *next;
};
/* prototypes */
void ins(struct node *llist, int number);
void rem(struct node *llist);
void sho(struct node *llist);
int main(void)
{
int number;
char command[6];
struct node *llist;
struct node *root;
llist = (struct node *)malloc(sizeof(struct node));
llist->number = 0;
llist->next = NULL;
root = llist;
printf("addr: \n\n%p,%p\n\n", &llist, &root);
FILE *file;
file = fopen("a3data.txt", "r");
if (file == NULL)
{
printf("\n----------------------------------------\n");
printf("| Error. Did not read file. Exiting. |\n");
printf("----------------------------------------\n\n");
exit(1);
}
else
{
while ((fscanf(file, "%s", command)) != EOF)
{
if((strcmp(command, "INSERT"))==0)
{
fscanf(file, "%d", &number);
printf("\nINSERT ", number);
ins(llist, number);
sho(llist);
}
else if((strcmp(command, "REMOVE"))==0)
{
printf("\n REMOVE ");
rem(llist);
sho(llist);
}
}
}
printf("\n");
free(llist);
return(0);
}
void ins(struct node *llist, int number)
{
while(llist->next != NULL)
{
llist = llist->next;
}
llist->next = (struct node *)malloc(sizeof(struct node));
llist->next->number = number;
llist->next->next = NULL;
}
void rem(struct node *llist)
{
while(llist->next->next != NULL)
{
llist = llist->next;
}
llist->next = NULL;
}
void sho(struct node *llist)
{
while(llist->next != NULL)
{
printf("%d ", llist->number);
llist = llist->next;
}
printf("%d", llist->number);
}
Modified function in your case
void ins(struct node *llist, int number)
{
struct node *llist1;
while(llist->next != NULL)
{
if (llist->next->number > number)
break;
llist = llist->next;
}
llist1 = (struct node *)malloc(sizeof(struct node));
llist1->number = number;
llist1->next = llist->next;
llist->next = llist1;
}
Your insert is simply adding the element in the tail. You have to write code to compare the present value of node(list->number) against the number to be inserted. If the current value is greater than the number to be inserted, then the number has to be inserted before the current node. For this, you will have to keep previous pointer also. The code, I have written, is just to understand the logic, Didn't check for correctness.
if(llist->number > innumber) {
node *newNode = (struct node *)malloc(sizeof(struct node);
newNode->number = innumber;
prevPointer->next = newNode;
newNode->next = llist;
}
in ins() function, instead of
while(llist->next != NULL)
use
while((llist->next != NULL) && (llist->number < number))
This will help you to sort while inserting itself.
Also in rem() function, you have to free the memory that you dynamically allocate.
Here is a program it is working
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next, *prev;
};
struct node *root = NULL;
void push(int);
void pop(void);
struct node *create_node(int);
void travel(void);
int main()
{
int i, j, choice, count;
printf("enter choice\n");
scanf("%d", &choice);
count = 0;
while (choice == 1) {
printf("enter a data element");
scanf("%d", &j);
if (count == 0) {
root = (struct node *)malloc(sizeof(struct node));
root->next = NULL;
root->data = j;
} else
push(j);
count++;
printf("enter choice\n");
scanf("%d", &choice);
}
printf("the link list is \n");
//travel function to be created
travel();
}
void push(int data)
{
struct node *t1;
t1 = root;
while (t1->next != NULL) {
t1 = t1->next;
}
t1->next = create_node(data);
}
void pop()
{
}
void travel(void)
{
struct node *t1;
t1 = root;
while (t1->next != NULL) {
printf("%d ", t1->data);
t1 = t1->next;
}
printf("%d ", t1->data);
}
struct node *create_node(int data)
{
struct node *p = (struct node *)malloc(sizeof(struct node));
p->data = data;
p->next = NULL;
p->prev = NULL;
return p;
}
the above program is fully working,I have used a global pointer root.
My problem is if I do not want to use a global pointer root here then how do I maintain
that list because each time I will have to return the root of list in my push pop functions
is there any other way to achieve the same?
The simplest way to achieve this is to pass a pointer to the root node pointer to each of your functions:
void push(struct node **root, int data) { ... }
void pop(struct node **root) { ... }
void travel(struct node *root) { ... }
So, in your main function you might declare a local variable to hold the root pointer:
struct node *root = NULL;
and then when you call push, for example, you pass the address of the root poiner:
push(&root, data);
I strongly recommend that you fix your push and travel functions so that they are robust to the root pointer being NULL. This was discussed in a previous question of yours and you should heed the advice.
If you did that then you could get rid of the test for count being zero and the associated special case code. You would then replace this:
if (count == 0) {
root = (struct node *)malloc(sizeof(struct node));
root->next = NULL;
root->data = j;
} else
push(&root, j);
with this:
push(&root, j);
To drive home the message, your new push would look like this:
void push(struct node **root, int data)
{
if (*root == NULL)
*root = create_node(data);
else
{
struct node *last = *root;
while (last->next != NULL) {
last = last->next;
}
last->next = create_node(data);
}
}
You would need to modify travel also to include a check for the root node being NULL. I will leave that as an exercise for you.
Maintaining both head and tail pointers could be a better approach since it would avoid so many list traversals.