I recently wrote a fairly simple piece of code attempting to implement a Binary Search Tree in C with insertion, search, deletion and display operations. Unfortunately, the code does not seem to work.
#include <stdio.h>
#include <stdlib.h>
struct TreeNode {
int data;
struct TreeNode *leftChildNode;
struct TreeNode *rightChildNode;
};
typedef struct TreeNode node;
node *rootNode = NULL;
void insertNode(int i, node *n) {
if(n == NULL) {
n = (node*)malloc(sizeof(node));
n->leftChildNode = NULL;
n->rightChildNode = NULL;
n->data = i;
}
else
if(n->data == i)
printf("\nThis value already exists in the tree!");
else
if(i > n->data)
insertNode(i, n->rightChildNode);
else
insertNode(i, n->leftChildNode);
}
void searchNode(int i, node *n) {
if(n == NULL)
printf("\nValue does not exist in tree!");
else
if(n->data == i)
printf("\nValue found!");
else
if(i > n->data)
searchNode(i, n->rightChildNode);
else
searchNode(i, n->leftChildNode);
}
void deleteNode(int i, node *n) {
if(n == NULL)
printf("\nValue does not exist in tree!");
else
if(n->data == i) {
if(n->leftChildNode == NULL)
n = n->rightChildNode;
else
if(n->rightChildNode == NULL)
n = n->leftChildNode;
else {
node *temp = n->rightChildNode;
while(temp->leftChildNode != NULL)
temp = temp->leftChildNode;
n = temp;
}
}
else
if(i > n->data)
deleteNode(i, n->rightChildNode);
else
deleteNode(i, n->leftChildNode);
}
void displayPreOrder(node *n) {
if(n != NULL) {
printf("%d ", n->data);
displayPreOrder(n->leftChildNode);
displayPreOrder(n->rightChildNode);
}
}
void displayPostOrder(node *n) {
if(n != NULL) {
displayPostOrder(n->leftChildNode);
displayPostOrder(n->rightChildNode);
printf("%d ", n->data);
}
}
void displayInOrder(node *n) {
if(n != NULL) {
displayInOrder(n->leftChildNode);
printf("%d ", n->data);
displayInOrder(n->rightChildNode);
}
}
int main(void) {
int ch, num, num1;
do {
printf("\nSelect a choice from the menu below.");
printf("\n1. Insert a node.");
printf("\n2. Search for a node.");
printf("\n3. Delete a node.");
printf("\n4. Display the Binary Search Tree.");
printf("\nChoice: ");
scanf("%d", &ch);
switch(ch) {
case 1: printf("\nEnter an element: ");
scanf("%d", &num);
//printf("YESYES");
insertNode(num, rootNode);
break;
case 2: printf("\nEnter the element to be searched for: ");
scanf("%d", &num);
searchNode(num, rootNode);
break;
case 3: printf("\nEnter the element to be deleted: ");
scanf("%d", &num);
deleteNode(num, rootNode);
break;
case 4: printf("\nSelect an order for the elements to be display in.");
printf("\n1. Pre-order.");
printf("\n2. Post-order.");
printf("\n3. In-order.");
printf("\nChoice: ");
scanf("%d", &num1);
switch(num1) {
case 1: printf("\nPre-order Display: ");
displayPreOrder(rootNode);
break;
case 2: printf("\nPost-order Display: ");
displayPostOrder(rootNode);
break;
case 3: printf("\nIn-order Display: ");
displayInOrder(rootNode);
break;
default: exit(0);
}
break;
default: exit(0);
}
//printf("%d", rootNode->data);
printf("\nIf you want to return to the menu, press 1.");
printf("\nChoice: ");
scanf("%d", &num);
} while(num == 1);
return 0;
}
In fact, notice the commented line printf("%d", rootNode->data); just before the do-while block in main() ends. If I uncomment this line, compile the program and run it, the program throws a segmentation fault. Could anyone tell me why this error is occurring and why the code as a whole isn't running? Thanks in advance.
You have a misconception about the way C handles arguments. In C, all arguments are passed by value, including pointers. When you reassign a pointer inside of a function you are reassigning a copy of that pointer.
For instance:
void f ( int *p );
int *p;
f(p);
The address (&p) of the pointer is different in the function. They both point to the same location (have the same value), but each has a different address. When you assign the pointer to the return value of malloc, it is only assigning the function local copy of that pointer.
One way to fix this is to introduce another level of indirection, and pass the address of the pointer: void insertNode(int i, node **n), which you can call like insertNode(0, &n). When you want to change it to something else, dereference it once and then assign: *p = malloc(sizeof(node)).
Another solution is to have the function return the pointer and assign it in the calling code: return malloc(sizeof(node)). (Note: You would actually return it after the initialization code... also don't cast the return value of malloc in C).
At the top, you declare
node *rootNode = NULL;
If you don't run insertNode (successfully - See Matt's answer), the node will still be NULL when trying to print it and that's why you're getting the segfault.
The reason why the code segfaults when you uncomment the printf statement is because rootNode is a NULL pointer. Dereferencing this NULL pointer in the function call causes the segfault.
The reason that rootNode is a NULL pointer is that it is never changed by the code. Calling insertNode() results in the local variable n being set to the value that is stored in rootNode (in this case NULL). The changes to n in the insertNode() function do not change rootNode.
To fix the code you could change the insertNode and deleteNode functions to accept a pointer to the root node pointer. For example the insertCode() function would become:
void insertNode(int i, node **n) {
if(*n == NULL) {
(*n) = (node*)malloc(sizeof(node));
(*n)->leftChildNode = NULL;
(*n)->rightChildNode = NULL;
(*n)->data = i;
}
else
{
if((*n)->data == i)
{
printf("\nThis value already exists in the tree!");
}
else
{
if(i > (*n)->data)
insertNode(i, &(*n)->rightChildNode);
else
insertNode(i, &(*n)->leftChildNode);
}
}
}
You would also have to change the code to call insertNode() with a reference to rootNode insertNode(num, &rootNode);
I also recommend that you check the return values of the various scanf calls. If scanf("%d",x) returns 0 then the value not be converted to an int and the contents of x are undefined. Ideally the code would handle this case gracefully.
I think the probblem is with the signature for Insert function Try the below code and It will work
void insertNode(int i, node **n) {
if(*n == NULL) {
*n = (node*)malloc(sizeof(node));
(*n)->leftChildNode = NULL;
(*n)->rightChildNode = NULL;
(*n)->data = i;
}
else
if((*n)->data == i)
printf("\nThis value already exists in the tree!");
else
if(i > (*n)->data)
insertNode(i, &((*n)->rightChildNode));
else
insertNode(i, &((*n)->leftChildNode));
}
And use Insert Function as
insertNode(num, &rootNode);
Earlier the changes remain in the function Insert only. Use double pointer inside.
Related
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
struct node {
int data;
struct node* nextptr;
} * manode;
void add();
void delete ();
void display();
int main()
{
int choice;
int echoice;
while (choice != 4) {
printf("\n \t ENTER YOUR CHOICE FOR SINGLE LINKED LIST ");
printf("\n \t 1. ADD ELEMENT ");
printf("\n \t 2. DISPLAY ELEMENT ");
printf("\n \t 3. DELETE ELEMENT ");
printf("\n \t 4. EXIT ");
scanf("%d", &choice);
switch (choice) {
case 1:
while (echoice != 0) {
add();
printf("\n DO YOU WANT TO CONTINUE 1/0 ");
scanf("%d", &echoice);
}
break;
case 2:
display();
break;
case 3:
delete ();
break;
case 4:
exit(0);
break;
default:
printf("\n \t WRONG VALUE ENTERED ");
};
}
return 0;
}
#Add function is responsible to add the first node and all the remaining nodes as well.
void add()
{
struct node *tmp, *tmp2;
tmp = malloc(sizeof(struct node));
tmp2 = malloc(sizeof(struct node));
int value;
printf(" ENTER THE VALUE YOU WANT TO ENTER ");
scanf("%d", &value);
if (manode == NULL) {
manode = malloc(sizeof(struct node));
printf(" FIRST ENTRY ");
manode->data = value;
manode->nextptr = NULL;
tmp = manode;
printf("THE DATA %d ", manode->data);
}
else {
if (tmp2 == NULL) {
printf("\n MEMORY ALLOCATION FAILED");
}
else {
tmp2->data = value;
tmp2->nextptr = NULL;
tmp->nextptr = tmp2;
tmp = tmp->nextptr;
}
}
//manode=tmp;
}
void display()
{
struct node* tmp1;
if (manode == NULL) {
printf(" MEMORY ALLOCATION FAILED ");
}
else {
tmp1 = manode;
while (tmp1 != NULL) {
printf("\n%d DATA IS DISPLAY \n", tmp1->data);
tmp1 = tmp1->nextptr;
}
}
}
void delete ()
{
struct node* tmp;
if (manode == NULL) {
printf("NOTHING TO DELETE ");
}
else {
tmp = malloc(sizeof(struct node));
}
}
Kindly copy and compile the code, it's working but it doesn't display the contents in the list. Kindly copy and compile the code, it's working but it doesn't display the contents in the list.Kindly copy and compile the code, it's working but it doesn't display the contents in the list.Kindly copy and compile the code, it's working but it doesn't display the contents in the list.
As I see, there are a number of issues with your code.
do not use conio.h. This thing is from the '80s and adds nothing to a modern program but problems
never try to implement an ADT --- any container such as list, set, map --- as a node. It will only give you trouble: a list is a collection of nodes. Each node has a payload, some data. This data can have a key, something used to compare records. A node is not a list. A node is not the data. A list is not a node. As seen from the list, the data are the nodes. This way you can use anything as data in your list. And this is the purpose of a container: write once, use always. And the list has metadata, some obvious controls such its size, starting addres, ending address and possibly other stuff.
do not use void(). Is a waste, sometimes an error. In your case is an error. All pointers are buried inside the functions and die there. So display() and add() does not work
do not typedef pointers. It is a mess. In you case manode is a pointer. How are someone, even yourself a few days from now, remember what is what? If manode is a typedef for a struct everyone knows that
manode* many_nodes[30]
declare many_nodes as a pointer to an array of structs. The asterisk tells everything: many_nodes is a pointer to manode. BTOS if you bury the * inside the typedef you will always need to refer to the code in the header.
do not mix code of the list with I/O. It will only make your like harder. You have a list of simple int, so declare add() for instance as int add(int item, List* the_list). This way is more readable and you can write a simple loop to fill the list with a few hundred or just one node and start testing.
if you have a menu just write it as a function that returns the user option. But add it later to the program. A menu serves nothing to the list and to the program
scanf() was not written to read input from the keyboard. It is for scan formatted input, hence the name. It will always give you trouble when reading from stdin. But do your part and at least always test the return of scanf(). ALWAYS. rtfm.
do not write \n \t on a printf. Use just tabs or count the spaces.
always initialize all variables. In your code you start testing choice and echoice with no value set.
what is the point of having a loop on option 1, add since anyway the user will need to input an answer and enter 1?
Back to your program
See below your code rearranged using some of the things I wrote above. Compare with your code
Sample Code
#include <stdio.h>
#include <stdlib.h>
typedef struct st_node
{
int data;
struct st_node* nextptr;
} Node;
typedef struct tlist
{
unsigned size;
Node* start;
} List;
int add(int, List*);
int delete (int, List*);
int display(List*);
int menu();
int main(void)
{
List one;
one.size = 0;
one.start = NULL;
int res = menu();
printf("menu returned %d\n", res);
display(&one);
for( int i = 0; i<10; i+=1)
add(i,&one);
display(&one);
return 0;
}
int add(int value, List* l)
{
if ( l == NULL ) return -1;
Node* node = (Node*) malloc(sizeof(Node));
// simplest: insert at the beginning
node->nextptr = l->start;
node->data = value;
l->start = node;
l->size += 1;
return l->size;
};
int display(List* l)
{
if ( l== NULL) return -1;
if ( l->size == 0 )
{
printf("\n\tlist is empty\n\n");
return 0;
}
else
{
printf("\n\t%d elements in the list\n\n", l->size);
};
Node* p = l->start;
for( unsigned i = 0; i< l->size; i+=1)
{
printf("%3d: %11d\n", 1+i, p->data);
p = p->nextptr;
};
return l->size;
}
int delete (int v, List* l)
{
return 0;
}
int menu()
{
int choice = 0;
int res = 0;
printf(
"\n\tENTER YOUR CHOICE FOR SINGLE LINKED LIST:\n\
\n\t\t1. ADD ELEMENT\
\n\t\t2. DISPLAY ELEMENT\
\n\t\t3. DELETE ELEMENT\
\n\t\t4. EXIT\
\n\n\t\tYour choice: ");
while( res != 1 )
{
res = scanf("%d", &choice);
if ( choice >=1 && choice <= 4 ) return choice;
};
return 4;
}
OUTPUT
ENTER YOUR CHOICE FOR SINGLE LINKED LIST:
1. ADD ELEMENT
2. DISPLAY ELEMENT
3. DELETE ELEMENT
4. EXIT
Your choice: 2
menu returned 2
list is empty
10 elements in the list
1: 9
2: 8
3: 7
4: 6
5: 5
6: 4
7: 3
8: 2
9: 1
10: 0
And it is just an example of stuff using a more manageable list.
This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 3 years ago.
I am currently trying to implement a Linked List in C. However, my function to create the head is not working apparently, since my other function to add a new node throws a dereferencing null pointer exception. Also, the size variable that keeps the amount of nodes is not being increased. Here is my full code.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
typedef struct node {
int val;
struct node* next;
} Node;
void printView(int);
bool terminate();
void createHead(Node*, int);
void addNext(Node*, int);
int main()
{
srand(time(NULL));
int size = 0;
Node* head = NULL;
bool created = false;
bool end = false;
while (!end)
{
printView(size);
int choice;
scanf_s("%d", &choice);
switch (choice)
{
case 1:
{
if (!created)
{
createHead(head, size);
created = true;
}
else
printf("The head has already been created \n");
break;
}
case 2:
{
if (created)
addNext(head, size);
else
printf("The head needs to be created first \n");
break;
}
case 0:
{
bool t = terminate();
if (t)
end = true;
break;
}
}
}
return 0;
}
void printView(int size)
{
printf("Welcome to Linked Lists! - %d Nodes in List\n", size);
printf(" Type 1 to create a head \n");
printf(" Type 2 to create a new node \n");
printf(" Type 0 to exit \n");
}
bool terminate() //Exit
{
int save;
printf("Would you like to save your Linked List? \n(Enter 1 to save or 0 for not to save) \n");
scanf_s("%d", &save);
if (save == 1)
{
printf("The Linked List has been saved. It will show up next time you start the program \n");
}
else if (save == 0)
printf("Goodbye! \n");
else
{
printf("Please type a valid option \n");
return false;
}
return true;
}
void createHead(Node* head, int size)
{
head = malloc(sizeof(Node));
if (head == NULL) {
printf("Failed to create head, aborting operation \n");
return;
}
printf("Type a value for the new node: \n(It must be an integer / Type 0 to assign a random number) \n");
int value; scanf_s("%d", &value);
if (value == 0)
{
value = rand() % 11;
head->val = value;
printf("Value set to: %d \n", value);
}
else
head->val = value;
head->next = NULL;
size++;
}
void addNext(Node* node, int size)
{
Node* current = node;
while (current->next != NULL)
current = current->next;
current->next = malloc(sizeof(Node));
if (current->next == NULL)
{
printf("Failed to create new node, aborting operation \n");
return;
}
printf("Type a value for the new node: \n(It must be an integer / Type 0 to assign a random number) \n");
int value; scanf_s("%d", &value);
if (value == 0)
{
value = rand() % 11;
current->val = value;
printf("Value set to: %d \n", value);
}
else
current->val = value;
current->next = NULL;
size++;
}
The function create_head only modifies its arguments, not the variables in the calling function main. You should change the prototype to bool createHead(Node **headp, int *sizep) and update the values indirectly`.
There are other problems:
some include files are missing
the same problem in add_next() prevents size from getting updated in main.
passing the address of head to addNext removes the need for a separate function to create the initial list node.
it would be safer to define a List structure with a head and a size fields and pass that to the different functions.
Here is a modified version:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node {
int val;
struct node *next;
} Node;
void printView(int size);
bool terminate(void);
bool createHead(Node **headp, int *sizep);
bool addNext(Node **headp, int *sizep);
int main() {
srand(time(NULL));
int size = 0;
Node *head = NULL;
bool created = false;
bool end = false;
while (!end) {
printView(size);
int choice;
scanf_s("%d", &choice);
switch (choice) {
case 1:
if (!created) {
created = createHead(&head, &size);
} else {
printf("The head has already been created \n");
}
break;
case 2:
if (created)
addNext(&head, &size);
else
printf("The head needs to be created first \n");
break;
case 0:
end = terminate();
break;
}
}
}
return 0;
}
void printView(int size) {
printf("Welcome to Linked Lists! - %d Nodes in List\n", size);
printf(" Type 1 to create a head \n");
printf(" Type 2 to create a new node \n");
printf(" Type 0 to exit \n");
}
bool terminate(void) {
int save = 0;
printf("Would you like to save your Linked List? \n"
"(Enter 1 to save or 0 for not to save) \n");
scanf_s("%d", &save);
if (save == 1) {
// XXX: save the list
printf("The Linked List has been saved. It will show up next time you start the program \n");
} else if (save == 0) {
printf("Goodbye! \n");
} else {
printf("Please type a valid option \n");
return false;
}
return true;
}
bool createHead(Node **headp, int *sizep) {
Node *head = malloc(sizeof(Node));
if (head == NULL) {
printf("Failed to create head, aborting operation \n");
*headp = head;
*sizep = 0;
return false;
}
printf("Type a value for the new node: \n"
"(It must be an integer / Type 0 to assign a random number) \n");
int value;
scanf_s("%d", &value);
if (value == 0) {
value = rand() % 11;
printf("Value set to: %d \n", value);
}
head->val = value;
head->next = NULL;
*headp = head;
*sizep = 1;
return true;
}
bool addNext(Node **headp, int *sizep) {
Node *new_node = malloc(sizeof(Node));
if (new_node == NULL) {
printf("Failed to create new node, aborting operation \n");
return false;
}
printf("Type a value for the new node: \n(It must be an integer / Type 0 to assign a random number) \n");
int value;
scanf_s("%d", &value);
if (value == 0) {
value = rand() % 11;
printf("Value set to: %d \n", value);
}
current->val = value;
current->next = NULL;
if (*headp == NULL) {
*headp = new_node;
} else {
Node *current = *headp;
while (current->next != NULL)
current = current->next;
current->next = new_node;
}
*sizep += 1;
return true;
}
My goal is to create a linked list and store elements inside that list.
struct node
{
int a;
struct node *b;
} p,*temp,*head;
void create ( struct node *temp)
{
char c;
temp = malloc (sizeof(struct node));
printf("enter data\n");
scanf(" %d",&temp->a);
printf("do you want to insert another node y/n\n");
scanf("%s", &c);
if (c=='y')
{
create(temp->b);
}
else if ( c=='n')
{
temp->b= NULL;
temp=&p;
return;
}
}
void traverse ( struct node *head)
{
while(head != NULL)
{
printf("%d ",head->a);
head=head->b;
}
}
int main ()
{
int i,j,k,l,m,n;
do{
if(i==1)
{
printf("enter data\n");
scanf("%d",&p.a);
create (p.b);
}
else if ( i==2)
traverse(temp);
}
while(i!=3);
printf("%d",temp->a);
}
I can't recover the elements once i've stored them. When I try to traverse the list, it only gives me the first element of the list and nothing else.
In main
do {
if(i==1)
{
...
}
else if ( i==2)
traverse(temp);
}
while(i!=3);
must be something like
do {
if (scanf("%d", &i) != 1)
break;
if(i==1)
{
...
}
else if ( i==2)
traverse(temp);
}
while(i!=3);
to know what the user want (i not initialized in your code)
in create
scanf("%s", &c);
is wrong because c is a char rather than a string
Do not mix read of int and char because you will read newline and space when reading a character, so read a string for c, for instance
char c[2];
...
scanf("%1s", &c);
if (*c == 'y')
...
else if (c == 'n')
...
the return in else branch is useless, and in case the answer is not 'y' or 'n' you do nothing so you do not set temps, probably you have to just check if 'y' and all other answers must be considered to be 'n', or you need to ask again for the choice
in create you assign the local variable temps, that has no effect on p.b in main, you need to get a node** for instance
in main temp is used but never set elsewhere, and the variables j,k,l,m,n are useless. You also ask for the data in main while you also do in create, must not be done in main. The way you manage your variables do not allow you to modify/print the list
I encourage you to not use global variables the must you can, and to not use the same name for a global and local variable like you do for temp and head because that do not help the reader of your code
A proposal solving the problems :
#include <stdlib.h>
#include <stdio.h>
struct node
{
int a;
struct node * b;
};
/* flush input up to the end of the line */
void flush()
{
int c;
while ((c = getchar()) != '\n') {
if (c == EOF)
exit(-1);
}
}
void create (struct node ** l)
{
/* go to the end of the list */
while (*l != NULL)
l = &(*l)->b;
for (;;) {
char c[2];
int v;
printf("enter data\n");
if (scanf("%d", &v) != 1) {
puts("invalid value");
flush();
}
else {
*l = malloc (sizeof(struct node));
(*l)->a = v;
(*l)->b = NULL;
l = &(*l)->b;
for (;;) {
printf("do you want to insert another node y/n\n");
scanf("%1s", c);
if (*c == 'y')
break;
else if (*c == 'n')
return;
}
}
}
}
void traverse ( struct node *head)
{
while(head != NULL)
{
printf("%d ",head->a);
head = head->b;
}
putchar('\n');
}
int main ()
{
int i;
struct node *head = NULL;
for (;;) {
puts("enter choice : 1 to create new node, 2 to print list, 3 to exit");
if (scanf("%d", &i) != 1)
flush();
switch(i) {
case 1:
create(&head);
break;
case 2:
traverse(head);
break;
case 3:
return 0;
default:
break;
}
}
}
Compilation and execution :
/tmp % gcc -pedantic -Wextra -Wall t.c
/tmp % ./a.out
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
enter choice : 1 to create new node, 2 to print list, 3 to exit
1
enter data
11
do you want to insert another node y/n
y
enter data
22
do you want to insert another node y/n
n
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
11 22
enter choice : 1 to create new node, 2 to print list, 3 to exit
1
enter data
3
do you want to insert another node y/n
n
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
11 22 3
enter choice : 1 to create new node, 2 to print list, 3 to exit
4
enter choice : 1 to create new node, 2 to print list, 3 to exit
3
I encourage you to add the free of the list
There are several issues here:
struct node
{
int a;
struct node *b;
} p,*temp,*head;
Why do you declare global variables and use it as function parameters ? Global variables are available globally, there is no need to pass them into functions. On the other hand, global variables should be avoided and used with care, so it would be better to create local variables (e.g. in main function) and pass them as parameters into next functions.
void create ( struct node *temp)
{
char c;
temp = malloc (sizeof(struct node));
printf("enter data\n");
scanf(" %d",&temp->a);
printf("do you want to insert another node y/n\n");
scanf("%s", &c);
if (c=='y')
{
create(temp->b);
}
else if ( c=='n')
{
temp->b= NULL;
temp=&p;
return;
}
}
This function looks wrong. temp function parameter is actually an internal function's variable, that is not an in/out parameter. In that case you can assign to the temp variable, but it will not for a list. Also temp function parameter shadows temp global variable. It is also a good think to return status of operation, usually '0' means no error, any other error value.
Another thing is to keep things as simple as possible. This will allow for more reuseability and goes with single responsibility principle. If function actually performs two tasks it should be split into two functions.
One more thing, you allocate memory dynamically but never free the memory. This will lead into memory losses.
A possible implementation of your list could be:
#include <stdio.h>
#include <stdlib.h>
typedef struct _node_t
{
int a;
struct _node_t * next;
} node_t;
static node_t * head = NULL;
static node_t * tail = NULL;
node_t * create(void)
{
node_t * temp = malloc(sizeof(node_t));
if (NULL == temp)
{
return NULL;
}
printf("Enter data\n");
scanf("%d", & temp->a);
return temp;
}
void append(node_t * data)
{
if (NULL == head)
{
head = tail = data;
}
else
{
tail->next = data;
tail = tail->next;
}
tail->next = NULL;
return;
}
int add_data(void)
{
node_t * data = NULL;
char answer = 'y';
data = create();
if (NULL == data)
{
return 1;
}
append(data);
return 0;
}
void traverse(void)
{
node_t * current = NULL;
for (current = head; current != NULL; current = current->next)
{
printf("%d ", current->a);
}
printf("\n");
return;
}
void cleanup(void)
{
node_t * current = head;
while (NULL != current)
{
head = head->next;
free(current);
current = head;
}
return;
}
int main(int argc, char ** argv)
{
int option = 3;
do
{
printf("Enter option:\n 1 - add data\n 2 - traverse list\n 3 - exit\n\n");
scanf("%i", & option);
switch (option)
{
case 1:
if (0 != add_data())
{
printf("ERROR:: Cannot allocate memory.\n");
cleanup();
return 1;
}
break;
case 2:
traverse();
break;
default:
if (option > 3)
{
printf("ERROR:: Improper option, try again.\n");
}
break;
}
}
while (option != 3);
cleanup();
return 0;
}
I tried making it as simple as possible and keeping your logic there.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
// create a new node
struct node* create(int data)
{
struct node *n = malloc(sizeof(struct node));
n->data = data;
n->next = NULL; // by default its not NULL, so we must set it
return n;
}
void traverse(struct node *head)
{
struct node *tmp = head;
while(tmp != NULL)
{
printf("%d\t",tmp->data);
tmp = tmp->next;
}
}
void cleanup(struct node *head)
{
struct node *cur = head;
struct node *next;
while(cur != NULL)
{
next = cur->next;
free(cur);
cur = next;
}
}
int main ()
{
int data;
struct node *head, *tmp;
// head node is always created
printf("enter data\n");
scanf("%d",&data);
head = tmp = create(data);
if(head == NULL) return -1;
// now we loop until we don't want to create any more nodes
while(1)
{
char another;
printf("do you want to insert another node y/n\n");
scanf(" %c", &another); // ignore all the previous whitespace
if(another == 'y')
{
printf("enter data\n");
scanf("%d",&data);
tmp->next = create(data);
tmp = tmp->next;
}
else break;
/*
// anything but 'y' breaks the loop, but it can be set to continue if neither 'y' nor 'n' was read:
else if(another == 'n') break;
else continue;
*/
}
traverse(head);
cleanup(head);
}
EDIT: as #Diodacus stated, i added cleanup and checking if malloc returned NULL
I was running a linked queue data structure in C using Code::Blocks IDE.
Below is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct LinkedQueue
{
int data;
struct LinkedQueue *next;
}Q;
Q *front , *rear;
int QEmpty( Q * );
void QInsert();
Q *QDelete();
void QDisplay( Q* );
int main()
{
int ans, choice;
front = NULL;
rear = NULL;
do
{
printf("\n::Linked Queue Menu::");
printf("\n 1. Insert ");
printf("\n 2. Delete ");
printf("\n 3. Display ");
printf("\n 4. Exit ");
printf("\n Enter your choice:");
scanf("%d", &choice);
switch( choice )
{
case 1: QInsert();
break;
case 2: front = QDelete();
break;
case 3: QDisplay(front);
break;
case 4: exit(0);
}
printf("\nDo you want to go to main menu? (1/0) :");
scanf("%d", &ans);
}while ( ans == 1 );
return 0;
}
void QInsert()
{
Q *temp;
temp = (Q*)malloc(sizeof(Q));
temp->next = NULL;
if( temp == NULL)
{
printf("\nMemory cannot be allocated");
return;
}
printf("\nEnter the data:");
scanf("%d", &temp->data);
if( QEmpty( front ) )
{
front = temp;
rear = temp;
}
else
{
rear->next = temp;
rear = rear->next;
}
printf("\nInsertion Successful");
}
int QEmpty( Q *front )
{
if( front == NULL )
return 1;
else
return 0;
}
Q *QDelete()
{
Q *temp;
temp = front;
if( QEmpty( front ) )
{
printf("\nQueue Underflow!!");
printf("\nReturning to main menu . . ");
return NULL;
}
else
{
printf("\nThe deleted element is %d.", temp->data);
front = front->next;
temp->next = NULL;
free( temp );
}
return front;
}
void QDisplay( Q *front )
{
if( QEmpty( front ) )
{
printf("\nThe Queue is empty");
}
printf("\nThe display of Queue is:\n");
printf("!!!->");
do
{
printf("%d", front->data);
front = front->next;
}while( front != rear );
}
When I ran this program, the insertion and deletion functions works fine. But when I called the display function, it resulted into a segmentation fault (core dumped).
Please help me how to solve this error.
Thanks in advance.
The answer from #evolvedmicrobe shows a bug in QDisplay in case your list is empty (i.e. when front is NULL).
This answer will focus on another bug in QDisplay.
Consider what will happen when the list contains exactly 1 element. In that case front and rear are identical. Further front->next is NULL.
So look at my comment in the order 1), 2), 3) and 4):
void QDisplay( Q *front )
{
if( QEmpty( front ) )
{
printf("\nThe Queue is empty");
}
printf("\nThe display of Queue is:\n");
printf("!!!->");
do
{
printf("%d", front->data); // 1) In first loop this will print the data from the first element (fine)
// 4) In the second loop you deference front which is NULL => seg fault
front = front->next; // 2) Now front gets the value NULL
}while( front != rear ); // 3) Front and rear differs so the loop continuees
}
(note: besides causing a bug when there is exactly 1 element, your approach is also bad for "more than 1 element" as you will never print the last element)
A better approach is:
void QDisplay( Q *front )
{
if( QEmpty( front ) )
{
printf("\nThe Queue is empty");
return;
}
printf("\nThe display of Queue is:\n");
printf("!!!->");
do
{
printf("%d", front->data);
front = front->next;
}while( front != NULL ); // or just } while(front);
}
Additional consideration:
Your code uses the global variable front and rear. In general I'll recommend that you do not use global variables. It's confusing and error prone. Instead you can define them in main and pass pointers to them to functions that need to change them. Or - perhaps better - place them in a struct so you can pass a pointer to a variable of that struct (define in main).
If you really, really, really think you need global variables, I'll strongly recommend that you never use the same name for local variables and function arguments. In other words: You QDisplay currently has an argument with the name front - just like the global variable front. That's kind of confusing... what will happen when you assign something to front inside QDisplay? Will the global front change? The answer is no but to avoid confusion it's better to use another name for the function argument. Like:
void QDisplay( Q *p )
{
if( QEmpty( p ) )
{
printf("\nThe Queue is empty");
return;
}
printf("\nThe display of Queue is:\n");
printf("!!!->");
do
{
printf("%d", p->data);
p = p->next;
}while( p != NULL ); // or just } while(p);
}
In your function QDisplay, you check if a pointer is null, but don't exit if that condition is true, but instead go on to dereference the pointer, which will cause a segfault. You need to modify the method to return if queue is empty. E.g.
void QDisplay( Q *front )
{
if( QEmpty( front ) )
{
printf("\nThe Queue is empty");
// Two lines below added by me
printf("\nReturning to main menu . . ");
return;
}
...
The problem was solved. A guy gave it in comments. The problem was that I was using %d to read in a short int. I should have used %hd or I should have used an `int'.
I tried to create a program of singly-linked list using only local variables. I was able to make a working program by using global variables.
The program with local variables compiles but it crashes when I try to traverse the linked list.
I have absolutely no idea what is wrong with the implementation with local variables. What is the problem present in the Implementation with local variables?
ABOUT THE STRUCTURE OF THE PROGRAMS:
I understand that the programs are big so I'll put in something about structure of the program.
The program is structured as a menu driven program. So the initial calls to functions are in main() function
There are 3 options in main() menu - exit, traverse and insertion
Exit returns 0 to exit program while other 2 do function calls
Insertion function itself is arranged as menu-driven program.
It has 3 options - return , insert_begin and insert_end. The last 2 are function calls.
I know there are memory leaks as I haven't freed any memory but I will take care of that after I can understand the problem in the current program.
//WORKING IMPLEMENTATION USING GLOBAL VARIABLE
#include<stdio.h>
#include<stdlib.h>
#define MIN 0
#define MAX 2
#define INS_MIN 0
#define INS_MAX 2
typedef struct node
{
int data;
struct node *next;
}sll_node;
sll_node *start = NULL;
void intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Exit");
printf("\n\t01 Traverse the list");
printf("\n\t02 Insertion into the list");
}
void insert_begin()
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-1);
}
int data;
printf("\n\tData to be entered: ");
scanf("%d", &data);
node->data = data;
node-> next = start;
start = node;
}
void insert_end()
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-2);
}
if(start == NULL)
insert_begin();
else
{
printf("\n\tData to be entered: ");
scanf("%d", &(node->data));
node-> next = NULL;
sll_node *node2;
for(node2 = start; node2->next != NULL; node2 = node2->next)
;
node2->next = node;
}
}
void insert_intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Insertion Done");
printf("\n\t01 Insert at beginning");
printf("\n\t02 Insert at end");
}
void insertion()
{
short choice;
while(1)
{
choice = -1;
while(choice < INS_MIN || choice > INS_MAX)
{
insert_intro();
printf("\n\n\tEnter your chocie: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return;
case 1:
insert_begin();
break;
case 2:
insert_end();
break;
}
}
}
void traverse()
{
if(start == NULL)
printf("\n\n\tLinked list is empty");
else
{
printf("\n\n\t");
for(sll_node *node = start; node != NULL; node = node->next)
printf("%d ", node->data);
}
getch();
}
int main()
{
short choice;
while(1)
{
choice = -1;
while(choice < MIN || choice > MAX)
{
intro();
printf("\n\n\tEnter your choice: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return 0;
case 1:
traverse();
break;
case 2:
insertion();
break;
}
}
return 0;
}
//COMPILES BUT CRASHES - Same program but with local variable start and variable passing between functions
#include<stdio.h>
#include<stdlib.h>
#define MIN 0
#define MAX 2
#define INS_MIN 0
#define INS_MAX 2
typedef struct node
{
int data;
struct node *next;
}sll_node;
void intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Exit");
printf("\n\t01 Traverse the list");
printf("\n\t02 Insertion into the list");
}
sll_node* insert_begin(sll_node *start)
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-1);
}
int data;
printf("\n\tData to be entered: ");
scanf("%d", &data);
node->data = data;
node-> next = start;
return node;
}
sll_node* insert_end(sll_node *start)
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-2);
}
if(start == NULL)
start = insert_begin(start);
else
{
printf("\n\tData to be entered: ");
scanf("%d", &(node->data));
node-> next = NULL;
sll_node *node2;
for(node2 = start; node2->next != NULL; node2 = node2->next)
;
node2->next = node;
}
return start;
}
void insert_intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Insertion Done");
printf("\n\t01 Insert at beginning");
printf("\n\t02 Insert at end");
}
sll_node* insertion(sll_node *start)
{
short choice;
while(1)
{
choice = -1;
while(choice < INS_MIN || choice > INS_MAX)
{
insert_intro();
printf("\n\n\tEnter your chocie: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return start;
case 1:
start = insert_begin(start);
break;
case 2:
start = insert_end(start);
break;
}
}
}
void traverse(sll_node *start)
{
if(start == NULL)
printf("\n\n\tLinked list is empty");
else
{
printf("\n\n\t");
for(sll_node *node = start; node != NULL; node = node->next)
printf("%d ", node->data);
}
getch();
}
int main()
{
sll_node *start = NULL;
short choice;
while(1)
{
choice = -1;
while(choice < MIN || choice > MAX)
{
intro();
printf("\n\n\tEnter your choice: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return 0;
case 1:
traverse(start);
break;
case 2:
start = insertion(start);
break;
}
}
return 0;
}
You are not returning anything from insertion() function when item is added to a list. So linked list may not get constructed properly.
Probably, you should return start only when its added at the beginning, otherwise start in main() will not point to head of the list.
sll_node* insertion(sll_node *start)
{
...
switch(choice)
{
case 0:
return start;
case 1:
start = insert_begin(start);
return start; //<----- return node
break;
case 2:
start = insert_end(start);
break;
}
...
}
Change short choice to int choice.
Why does this make a difference?
Short answer is that printf("%d") expects an integer.
The long answer is "%d" describes the data type you are passing to printf as an integer (which is commonly 4 to 8 bytes), and you're giving it a datatype of short - which is commonly 2 bytes long. When your program reads the input and stores it at the pointer, &choice, it writes 4 bytes starting at that address (but only 2 were reserved). This causes a segmentation fault and will crash your program.
Here's a list to some printf documentation. You'll notice that to pass a short to printf you would write %hd instead of %d
When i compile your code on my computer, it works, but i changed "short choice" to "int choice", because scanf("%d", &choice) takes 4 bytes to write on, and when choice is short it crashes, because short has only 2 bytes, therefore stack corruption will occur, my be on your computer this corruption damage the "start" pointer.
About the crash. Change the argument start in both functions insert_begin and insert_end to sll_node ** start, and when assigning new value, use the expression *start = your-new-value. It is because you have to pass a pointer to the local variable start which is also pointer. You do not need to change function traverse.
About memory leaks, let me to point-out that when you call insert_begin from inside insert_end, the node created from insert_end is left unused. before exit() and the return in main() you should free the list.
Yes, sorry. There was another bug hard to see. It was at 2 lines where you read (choice).
short choice;
...
// It is ERROR to use "%d" with (short choice), because the stack will
// be overwritten with unsuspected results. The format specifier "%hd"
// say to compiler that (&choice) point to a short 16-bit integer,
// not 32-bit
scanf("%hd", &choice);
This is slightly different version, tested, without memory leaks.
//
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define MIN 0
#define MAX 2
#define INS_MIN 0
#define INS_MAX 2
typedef struct node
{
int data;
struct node *next;
} sll_node;
void clear_list(sll_node** start)
{
assert(start != NULL);
sll_node* node = *start;
while (node != NULL)
{
sll_node* element = node;
node = element->next;
free(element);
}
*start = NULL;
}
void intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Exit");
printf("\n\t01 Traverse the list");
printf("\n\t02 Insertion into the list");
}
void insert_begin(sll_node** pstart)
{
sll_node* node = (sll_node*)malloc(sizeof(sll_node));
if (node == NULL)
{
printf("\n\tNot enough menory");
clear_list(pstart);
exit(-1);
}
int data;
printf("\n\tData to be entered: ");
scanf_s("%d", &data);//scanf
node->data = data;
node->next = *pstart;
// update the local variable start passed from main to point just inserted node
*pstart = node;
}
void insert_end(sll_node** start)
{
assert(start != NULL);
if (*start == NULL)
{
insert_begin(start);
}
else
{
sll_node* node = (sll_node*)malloc(sizeof(sll_node));
if (node == NULL)
{
printf("\n\tNot enough menory");
clear_list(start);
exit(-2);
}
printf("\n\tData to be entered: ");
scanf("%d", &(node->data));
node->next = NULL;
sll_node* node2;
for(node2 = *start; node2->next != NULL; node2 = node2->next)
;
node2->next = node;
}
}
void insert_intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Insertion Done");
printf("\n\t01 Insert at beginning");
printf("\n\t02 Insert at end");
}
void insertion(sll_node** start)
{
short choice;
while(1)
{
choice = -1;
while(choice < INS_MIN || choice > INS_MAX)
{
insert_intro();
printf("\n\n\tEnter your chocie: ");
scanf("%hd", &choice);
}
switch(choice)
{
case 0:
return;
case 1:
insert_begin(start);
break;
case 2:
insert_end(start);
break;
}
}
}
void traverse(sll_node *start)
{
if (start == NULL)
printf("\n\n\tLinked list is empty");
else
{
printf("\n\n\t");
for(sll_node *node = start; node != NULL; node = node->next)
printf("%d ", node->data);
}
getch();
}
int main()
{
sll_node *start = NULL;
short choice;
while(1)
{
choice = -1;
while(choice < MIN || choice > MAX)
{
intro();
printf("\n\n\tEnter your choice: ");
scanf("%hd", &choice);
}
switch(choice)
{
case 0:
clear_list(&start);
return 0;
case 1:
traverse(start);
break;
case 2:
insertion(&start);
break;
}
}
return 0;
}
P.S. Very hard to edit! I'm new here and do not have enough experience. Wasted a lot of time to edit!