Stack implimentation using Linkedlist in C - c

I have written a code in C language to implement a stack using LinkedList algorithm. Here is the code........
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
struct listNode {
int data;
struct listNode *next;
};
struct stack{
struct stack *top;
};
struct stack *createstk(){
struct stack *stk;
stk=malloc(sizeof(struct stack));
stk->top=NULL;
return stk;
}
void push(struct stack *stk,int data){
struct listNode *temp;
temp=malloc(sizeof(struct listNode));
if(!temp){
printf("heap overflow");
return;
}
temp->data=data;
temp->next=stk->top;
stk->top=temp;
}
int pop(struct stack *stk){
if(isEmpty(stk))
return INT_MIN;
int data;
struct listNode *temp;
temp= stk->top;
stk->top=stk->top->next;
data=temp->data;
delete(temp);
return data;
}
int peek(struct stack *stk){
if(isEmpty(stk))
return INT_MIN;
return stk->top->data;
}
int isEmpty(struct stack *stk){
return stk->top==NULL;
}
void deleteStack(struct stack *stk){
struct listNode *temp,*p;
p=stk->top;
while(p){
temp=p->next;
p=p->next;
free(temp);
}
free(stk);
}
int main(){
int i=0;
struct stack *stk=createstk();
for(i=0;i<=10;i++)
push(stk,i);
printf("Top Element is %d",peek(stk));
for(i=0;i<=10;i++){
printf("popped element is %d",pop(stk));
}
if(isEmpty(stk))
printf("stack is empty");
else
printf("stack is not empty");
deleteStack(stk);
return 0;
}
[warning]assignment from incompatible pointer type.
As you can see above in the picture. I am a newbie in coding world and facing this error first time. That's why I don't know what to do. Please tell me...

The field top in the type stack has the wrong type. Change
struct stack {
struct stack *top;
};
to
struct stack {
struct listNode *top;
};

Your have a large number of error beginning with the incorrect type for stack->top, as correctly noted by August Karlstrom your type for the member top must be struct listNode *top;, e.g.
struct stack {
struct listNode *top;
};
Following the correction, you must either reorder your functions or provide function prototypes for isEmpty() and deleteStack(). Moving them up in your code before before their first use will solve the problem, e.g.
struct stack *createstk()
{
struct stack *stk;
stk = malloc (sizeof (struct stack));
stk->top = NULL;
return stk;
}
int isEmpty (struct stack *stk)
{
return stk->top == NULL;
}
void deleteStack (struct stack *stk)
{
struct listNode *temp, *p;
p = stk->top;
while (p) {
temp = p->next;
p = p->next;
free (temp);
}
free (stk);
}
...
Next, this is C, not C++ there is no delete function to free memory, so in pop(), you must call free (temp); instead of delete (temp);.
Finally, provide spacing to make your code readable. Incorporating the above, you could do the following:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
struct listNode {
int data;
struct listNode *next;
};
struct stack {
struct listNode *top;
};
struct stack *createstk()
{
struct stack *stk;
stk = malloc (sizeof (struct stack));
stk->top = NULL;
return stk;
}
int isEmpty (struct stack *stk)
{
return stk->top == NULL;
}
void deleteStack (struct stack *stk)
{
struct listNode *temp, *p;
p = stk->top;
while (p) {
temp = p->next;
p = p->next;
free (temp);
}
free (stk);
}
void push (struct stack *stk, int data){
struct listNode *temp;
temp = malloc (sizeof *temp);
if (!temp) {
perror ("push()-malloc-temp");
return;
}
temp->data = data;
temp->next = stk->top;
stk->top = temp;
}
int pop(struct stack *stk){
int data;
struct listNode *temp;
if (isEmpty(stk))
return INT_MIN;
temp = stk->top;
data = temp->data;
stk->top = stk->top->next;
free (temp);
return data;
}
int peek(struct stack *stk){
if(isEmpty(stk))
return INT_MIN;
return stk->top->data;
}
int main (void) {
int i=0;
struct stack *stk=createstk();
for (i = 0; i <= 10; i++)
push(stk,i);
printf("Top Element is %d\n",peek(stk));
for (i = 0; i <= 10; i++)
printf (" popped element is %d\n",pop(stk));
if (isEmpty(stk))
printf ("stack is empty\n");
else
printf ("stack is not empty\n");
deleteStack(stk);
return 0;
}
Example Use/Output
$ ./bin/stack_ll
Top Element is 10
popped element is 10
popped element is 9
popped element is 8
popped element is 7
popped element is 6
popped element is 5
popped element is 4
popped element is 3
popped element is 2
popped element is 1
popped element is 0
stack is empty
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/stack_ll
==25935== Memcheck, a memory error detector
==25935== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==25935== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==25935== Command: ./bin/stack_ll
==25935==
Top Element is 10
popped element is 10
popped element is 9
popped element is 8
popped element is 7
popped element is 6
popped element is 5
popped element is 4
popped element is 3
popped element is 2
popped element is 1
popped element is 0
stack is empty
==25935==
==25935== HEAP SUMMARY:
==25935== in use at exit: 0 bytes in 0 blocks
==25935== total heap usage: 12 allocs, 12 frees, 184 bytes allocated
==25935==
==25935== All heap blocks were freed -- no leaks are possible
==25935==
==25935== For counts of detected and suppressed errors, rerun with: -v
==25935== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
If you have any further questions, just let me know.

Related

Why does the function named "traverse" not work on my code?

In the example below, I created a linked list and I can add numbers successfully. However, at the
end of the execution, the function named "traverse" does not work. How can I fix this error?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct node
{
int data;
struct node*prev;
struct node*next;
};
void add( node*head,int number )
{
node*ptr = NULL;
if( head == NULL )
{
head = (node*)malloc(sizeof(node));
head->data = number;
head->next = NULL;
head->prev = NULL;
ptr = head;
}
else
{
ptr->next = (node*)malloc(sizeof(node));
ptr->next->prev = ptr;
ptr = ptr->next;
ptr->data = number;
ptr->next = NULL;
}
}
void traverse( node* head )
{
while( head != NULL )
{
printf("%d ",head->data);
head = head->next;
}
}
int main( void )
{
node *head = NULL;
int number;
char response;
printf("%s\n","Do you want to enter a number in linked list(y/n)?" );
scanf("%c",&response);
while( response == 'y' || response == 'Y' )
{
printf("\nEnter num..> ");
scanf("%d",&number);
add(head,number);
printf("%s\n","Do you want to continue(y/n)?" );
response = getche();
}
printf("\nYour doubly linked list\n");
traverse(head);
getch();
return 0;
}
when "traverse" is called, the console print space like the following image.
If you have decided on C, then continuing from the comments, you are attempting to update a local copy of the pointer head in add(). As mentioned, you have two option, either change the return type of add() to node *add() so you can return ptr and assign as the new head back in main(), or pass the address of head as the first parameter and update the node stored at the original pointer address in add().
You can pass the address of head to add() as follows:
void add (node **head, int number)
{
node *ptr = malloc (sizeof *ptr);
if (!ptr)
return;
ptr->data = number; /* initialized new node data */
ptr->prev = ptr->next = NULL; /* initialized both pointers NULL */
if ( *head != NULL ) { /* if not 1st node */
(*head)->prev = ptr; /* Forward-Chain new node */
ptr->next = *head;
}
*head = ptr; /* set head = new node */
}
(note: since you pass the address of head as a parameter, you must remove one level of indirection from the pointer-to-pointer in add() by dereferncing head (e.g. *head) in order to update the node at the original pointer address. You also need to use the (*head) when further derferencing the pointer with -> due to C operator precedence -- so you get the original pointer address before -> is applied)
Note, the add() function uses a method call Forward-Chaining to add each node to the list in O(1) time. This also means the list will hold the numbers in the reverse order they were entered (last first). You have two options to insert in-order, (1) iterate to the end of the list each time and add a new end node (highly inefficient for large lists, no longer O(1) time, or (2) use another tail pointer that always points to the last node to allow in-order insertions in O(1) time.
You would then call your add() function in main() with
add (&head, number);
Do NOT make things difficult on yourself when testing your list implementation. There is no reason to have to type 'y' then a number and 'y' again before every number you add to your list (that would drive me nuts...). Just add numbers to your list with a loop, you can do input later, e.g.
int main (void)
{
node *head = NULL; /* list pointer initialized NULL */
for (int i = 0; i < 20; i++) /* just add 20 nodes to list */
add (&head, i + 1);
traverse (head);
delete_list (head);
head = NULL;
/* hold terminal open on windows only */
#if defined (_WIN32) || defined (_WIN64)
getchar();
#endif
}
(note: conio.h has been removed and getchar() used to hold the terminal open on windows. Since I'm on Linux, the final getchar() is not compiled as part of my executable)
Your traverse() function will work, but get in the habit of using a separate separate pointer to iterate over you list. This isn't always required, and isn't needed in traverse() since you can use the local copy of head, but always using a temporary pointer to iterate with leave you with the original head address if you need it for use later in your function, e.g.
void traverse (const node *head)
{
const node *iter = head; /* optional, but good practice */
while (iter) {
printf ("%d ", iter->data);
iter = iter->next;
}
putchar ('\n');
}
Notice also the delete_list() function added to free() all memory added for your list. You won't always be declaring lists in main() where the memory is freed on exit. Get in the habit of keeping track of the memory you allocate and freeing the memory before your pointer goes out of scope (otherwise, you will create a memory leak)
The full program would be:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *prev, *next;
} node;
void add (node **head, int number)
{
node *ptr = malloc (sizeof *ptr);
if (!ptr)
return;
ptr->data = number; /* initialized new node data */
ptr->prev = ptr->next = NULL; /* initialized both pointers NULL */
if ( *head != NULL ) { /* if not 1st node */
(*head)->prev = ptr; /* Forward-Chain new node */
ptr->next = *head;
}
*head = ptr; /* set head = new node */
}
void traverse (const node *head)
{
const node *iter = head; /* optional, but good practice */
while (iter) {
printf ("%d ", iter->data);
iter = iter->next;
}
putchar ('\n');
}
void delete_list (node *head)
{
node *iter = head;
while (iter) {
node *victim = iter;
iter = iter->next;
free (victim);
}
}
int main (void)
{
node *head = NULL; /* list pointer initialized NULL */
for (int i = 0; i < 20; i++) /* just add 20 nodes to list */
add (&head, i + 1);
traverse (head);
delete_list (head);
head = NULL;
/* hold terminal open on windows only */
#if defined (_WIN32) || defined (_WIN64)
getchar();
#endif
}
Example Use/Output
$ ./bin/llmess
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llmess
==16661== Memcheck, a memory error detector
==16661== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16661== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16661== Command: ./bin/llmess
==16661==
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
==16661==
==16661== HEAP SUMMARY:
==16661== in use at exit: 0 bytes in 0 blocks
==16661== total heap usage: 21 allocs, 21 frees, 1,504 bytes allocated
==16661==
==16661== All heap blocks were freed -- no leaks are possible
==16661==
==16661== For counts of detected and suppressed errors, rerun with: -v
==16661== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.

Segmentation fault / list initializing

I want to create a list with the following structure:
list.h: Contains function prototypes and defines data types
lt.c: main function to test the list
list.c: actual implementation of the list
When executing it I always get a segfault error. When trying to identify it with gdb it is shown that it is the fault of the following line in lt.c:
list_t *li=list_init();
The rest of my lt.c file looks as follows:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main ( int argc, char *argv [ ], char *envp [ ] )
{
list_t *li=list_init();
//li=list_init();
/* if((li=list_init())==NULL)
{
perror (" Cannot allocate memory" ) ;
exit(-1);
}*/
}
My implementation of the list.c function list_init() is as follows:
list_t *list_init ()
{
list_t* newlist = malloc(sizeof(*newlist));
if (!newlist)
{
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}`enter code here`
//newlist->first=NULL;
//newlist->last=NULL;
newlist->first = (struct list_elem *) malloc(sizeof(struct list_elem));
newlist->last = (struct list_elem *) malloc(sizeof(struct list_elem));
return newlist;
}
My list.h file is as follows:
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
However, I do not know how I could change the implementation so that it does not occur anymore.
Thank you very much for your help.
While it is impossible to tell where your problem lies exactly, I suspect it lies in one of two places. One, you are initializing each data member with a string literal which is read-only on all but a very few systems. So if anywhere in your code you attempt to modify data you could expect a SegFault. The same would apply if you later attempt to free (pointer->data);
Two, you fail of assign your node->next pointers correctly leading to your traversal attempting to derefernce a NULL pointer or indeterminate pointer leading to the same SegFault. This can occur if your append function fails to handle the if (!list->first) { ... } case correctly or the else case where you will be required to set pointer->next = newnode;
There is really no way to tell unless you post a A Minimal, Complete, and Verifiable Example (MCVE), but given list operations are somewhat generic, you could correct the shortcomings with something similar to the following for your init() and append() functions (with an added print() and free() functions thrown in for good measure), e.g.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);
int main (void)
{
list_t *li = list_init();
if (list_append (li, (char[]){"erstes"}) == NULL ||
list_append (li, (char[]){"zweites"}) == NULL ||
list_append (li, (char[]){"drittes"}) == NULL) {
perror ("Cannot allocate memory" ) ;
exit (EXIT_FAILURE);
}
list_print (li);
list_free (li);
exit (EXIT_SUCCESS);
}
list_t *list_init (void)
{
list_t *newlist = malloc (sizeof *newlist);
if (!newlist) {
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}
newlist->first = NULL;
newlist->last = NULL;
return newlist;
}
struct list_elem *list_append (list_t *list, char *data)
{
struct list_elem *node = NULL;
if (!list)
return NULL;
if (!(node = malloc (sizeof *node))) {
perror ("malloc-node");
return NULL;
}
node->data = data;
node->next = NULL;
if (!list->first)
list->first = node;
else {
struct list_elem *iter = list->first;
while (iter->next)
iter = iter->next;
iter->next = node;
}
return (list->last = node);
}
void list_print (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
printf ("%s\n", iter->data);
iter = iter->next;
}
}
void list_free (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
struct list_elem *victim = iter;
iter = iter->next;
free (victim);
}
free (list);
}
Example Use/Output
$ ./bin/ll_list_elem
erstes
zweites
drittes
Memory Use/Error Check
There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_list_elem
==22383== Memcheck, a memory error detector
==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==22383== Command: ./bin/ll_list_elem
==22383==
erstes
zweites
drittes
==22383==
==22383== HEAP SUMMARY:
==22383== in use at exit: 0 bytes in 0 blocks
==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==22383==
==22383== All heap blocks were freed -- no leaks are possible
==22383==
==22383== For counts of detected and suppressed errors, rerun with: -v
==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Using last pointer with Forward-Chaining
Since you have a last pointer there is no need for a generic iteration of the list to find the last pointer. I suspect you are intending to use forward-chaining. In that case, you can simply modify append() as follows:
if (!list->first)
list->first = node;
else
list->last->next = node;
(note: the list->last = node assignment is handled in the return)
i think you are not allocate memory in proper way.
TList *list_init()
{
TList *newList = (TList *) malloc(sizeof(TList));
newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
newList->last = (struct list_elem *) malloc(sizeof(struct list_elem));
newList->first->next= NULL;
newList->last->next= NULL;
return newList;
}

What is wrong with this program on reversing stack? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I made this program in c to reverse stack. but it is crashing. please help me figure out what is wrong. the program is working fine till taking inputs. but when reverse is called it crashes. i am not able to find the fault. all the memory is being allocated properly. so i dont think there is segmentation fault.
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int data;
struct Node *next, *prev;
}SNode;
typedef struct{
SNode *top;
int count;
}Stack;
int isEmpty(Stack *s){
return (s->count==0);
}
void push(Stack *s,int x){
SNode *temp = (SNode *)malloc(sizeof(SNode));
temp->next = s->top;
temp->prev = NULL;
s->top->prev = temp;
temp->data = x;
s->top = temp;
s->count++;
}
int pop(Stack *s){
if(isEmpty(s)){
printf("Underflow");
return;
}
SNode *temp = s->top;
s->top = s->top->next;
s->top->prev = NULL;
int a = temp->data;
free(temp);
s->count--;
return a;
}
void reverse(Stack *s,Stack *rs){
while(!isEmpty(s)){
int p = pop(s);
push(rs,p);
}
}
int main(){
Stack *s = (Stack *)malloc(sizeof(Stack));
Stack *rs = (Stack *)malloc(sizeof(Stack));
char p='y';
while(p=='y'){
int pu;
printf("Enter data to be pushed: ");
scanf(" %d",&pu);
push(s,pu);
printf("Do you want to push another number? y/n:");
scanf(" %c",&p);
}
reverse(s,rs);
printf("Top of reversed stack: %d",rs->top->data);
return 0;
}
I dont know what i changed. i rewrote the code, this time using singly linked list, now it works really fine. dont know how !!??
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int data;
struct node *next;
}SNode;
typedef struct{
int count;
SNode *top;
}stack;
int isEmpty(stack *s){
return (s->count==0);
}
void push(stack *s,int x){
SNode *temp = (SNode *)malloc(sizeof(SNode));
temp->data = x;
temp->next = s->top;
s->top=temp;
s->count++;
}
int pop(stack *s){
if(isEmpty(s)){
printf("Underflow");
return -1;
}
SNode *temp = s->top;
s->top = temp->next;
int a = temp->data;
free(temp);
s->count--;
return a;
}
void reverseStack(stack *s, stack *rs){
while(!isEmpty(s)){
push(rs,pop(s));
}
}
int main(){
stack *s = (stack *)malloc(sizeof(stack));
stack *rs = (stack *)malloc(sizeof(stack));
s->count = rs->count =0;
char p ='y';
while(p=='y'){
int x;
printf("Enter data to push: ");
scanf("%d",&x);
push(s,x);
printf("Do you want to push more data? : y/n");
scanf(" %c",&p);
}
reverseStack(s,rs);
printf("Top of reversed stack: %d",rs->top->data);
return 0;
}
You have a number of problems in your implementation of your stack. The first of which is in push(), when you call:
temp->next = s->top;
s->top is an uninitialized pointer whose value is indeterminate. That invokes Undefined Behavior. Since this occurs on your very first call to push(s, pu), you can have zero confidence in the operation of the remainder of your code.
Next, both your push and pop function fail to test and handle in an appropriate manner whether the node being pushed or popped is the first or last node in the stack. These must be handled differently as the handling of your prev and next pointers will depend on whether other nodes exist. (you can't assign a next or prev node if you are pushing the first node, and you can't assign a new top on pop if no more nodes exist.
(note: you also seem to have used prev and next in a somewhat inconsistent manner. As long as you use them consistently, it doesn't matter whether you use prev for the existing top on push or next. I tend to have prev pointing down the stack and next pointing from the bottom up - but you are free to do it the other way)
To properly handle the first and last node in your stack, you can do a simple check on isempty() or simply check if (s->top == NULL) or if (s->count == 0).
You also need to initialize all pointers and count when you allocate storage for your stack and nodes. Failure to initialize all values on allocation will likely lead to an inadvertent attempted read from an uninitialized value (invoking additional instances of Undefined Behavior).
To eliminate that possibility, you can create simply helper functions, say create_node and create_stack to allocate, and validate the allocation, initialize the needed values, and then to provide a meaningful return indicating success or failure. You could do something simple like the following:
snode *create_node (int x)
{
snode *tmp = malloc (sizeof *tmp);
if (!tmp) {
perror ("create_node: memory exhausted.");
return NULL;
}
tmp->data = x;
tmp->prev = tmp->next = NULL;
return tmp;
}
stack *create_stack (void)
{
stack *tmp = malloc (sizeof *tmp);
if (!tmp) {
perror ("create_stack: memory exhausted.");
return NULL;
}
tmp->top = NULL;
tmp->count = 0;
return tmp;
}
Now there are no possibilities of an uninitialized value.
(Also note: while not an error, the standard coding style for C avoids the use of camelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants. It is a matter of style -- so it is completely up to you, but failing to follow it can lead to the wrong first impression in some circles.)
With the helper functions defined, allocating and initializing your forward and reverse stacks in main() becomes a simple matter of:
int pu;
stack *s = create_stack();
stack *rs = create_stack();
if (!s || !rs) /* validate the return from create_stack */
return 1;
Having created your forward and reverse stack, you can then handle the first and last node cases in push() and pop() with the addition of a simple conditional as described above:
void push (stack * s, int x)
{
snode *temp = create_node (x);
if (!s->top) /* is the stack empty? */
s->top = temp;
else {
s->top->next = temp;
temp->prev = s->top;
s->top = temp;
}
s->count++;
}
and for pop(),
int pop (stack *s)
{
int x;
snode *temp;
if (isempty (s)) { /* checking empty as you did in original */
printf ("underflow");
return 0;
}
x = s->top->data;
temp = s->top;
if (s->top->prev)
s->top = s->top->prev;
s->top->next = NULL;
free (temp);
s->count--;
return x;
}
Adding a short prn_stack() function to iterate over the stack without poping and freeing the nodes, you could put together a short example program to test the push, pop and reverse as follows:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next, *prev;
} snode;
typedef struct {
snode *top;
int count;
} stack;
snode *create_node (int x)
{
snode *tmp = malloc (sizeof *tmp);
if (!tmp) {
perror ("create_node: memory exhausted.");
return NULL;
}
tmp->data = x;
tmp->prev = tmp->next = NULL;
return tmp;
}
stack *create_stack (void)
{
stack *tmp = malloc (sizeof *tmp);
if (!tmp) {
perror ("create_stack: memory exhausted.");
return NULL;
}
tmp->top = NULL;
tmp->count = 0;
return tmp;
}
int isempty (stack *s)
{
return (s->count == 0);
}
void prn_stack (stack *s)
{
snode *iter;
if (isempty(s)) {
puts ("stack empty");
return;
}
iter = s->top;
for (; iter; iter = iter->prev)
printf (" %d\n", iter->data);
}
void push (stack * s, int x)
{
snode *temp = create_node (x);
if (!s->top)
s->top = temp;
else {
s->top->next = temp;
temp->prev = s->top;
s->top = temp;
}
s->count++;
}
int pop (stack *s)
{
int x;
snode *temp;
if (isempty (s)) {
printf ("underflow");
return 0;
}
x = s->top->data;
temp = s->top;
if (s->top->prev)
s->top = s->top->prev;
s->top->next = NULL;
free (temp);
s->count--;
return x;
}
void reverse (stack * s, stack * rs)
{
while (!isempty (s))
push (rs, pop (s));
}
int main ()
{
int pu;
stack *s = create_stack();
stack *rs = create_stack();
if (!s || !rs)
return 1;
while (scanf (" %d", &pu) == 1)
push (s, pu);
printf ("stack:\n");
prn_stack (s);
reverse (s, rs);
printf ("\nreversed stack:\n");
while (!isempty (rs))
printf (" %d\n", pop (rs));
free (s);
free (rs);
return 0;
}
(note: do not forget to free the memory you allocate for your forward and your reverse stacks after all the values have been popped, and always validate your memory use by using a memory-error checking program like valgrind on Linux. There are similar programs for all OS's)
Example Use/Output
$ echo "10 9 8 7 6 5 4 3 2 1" | ./bin/stack_rev
stack:
1
2
3
4
5
6
7
8
9
10
reversed stack:
10
9
8
7
6
5
4
3
2
1
To validate your memory use and that you have freed all memory you allocate and that there are no memory errors, just run your code through the memory checker, similar to the following using valgrind, e.g.
Memory Use/Error Check
$ echo "10 9 8 7 6 5 4 3 2 1" | valgrind ./bin/stack_rev
==18418== Memcheck, a memory error detector
==18418== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18418== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==18418== Command: ./bin/stack_rev
==18418==
stack:
1
2
3
4
5
6
7
8
9
10
reversed stack:
10
9
8
7
6
5
4
3
2
1
==18418==
==18418== HEAP SUMMARY:
==18418== in use at exit: 0 bytes in 0 blocks
==18418== total heap usage: 22 allocs, 22 frees, 512 bytes allocated
==18418==
==18418== All heap blocks were freed -- no leaks are possible
==18418==
==18418== For counts of detected and suppressed errors, rerun with: -v
==18418== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Look things over and let me know if you have any further questions.
malloc doesn't initialize the struct members to zero and NULL. You have to do that yourself or use calloc instead. So change your malloc lines in your program to something like this:
Stack *s = calloc(1, sizeof(Stack));
Stack *rs = calloc(1, sizeof(Stack));
I see at least two problems.
When you malloc() a new Stack structure, you don't initialize the *top and count fields, and their contents is likely to be garbage.
In pop():
SNode *temp = s->top;
s->top = s->top->next;
s->top->prev = NULL;
What happens if the initial value of s->top->next is NULL?
Your code crashes randomly because s->count is not 0 when you first declare it in main. If you're lucky, s->count is 0, then your reverse is fine because isEmpty() will work correctly. Otherwise, you will get segmentation fault.

Creating a linked list using recursion

I want to create a linked list using recursion. After executing the code, I get only the value of the first node and rest are not being printed.
#include<stdio.h>
#include<malloc.h>
typedef struct node NODE;
struct node
{
int data;
struct node *next;
} *start=NULL,*ptr;
void display();
int create(int);
int main()
{
int n;
printf("\nEnter the no of node?\t");
scanf("%d",&n);
create(n);
display();
}
int create(int x)
{
if(x==0)
return;
else{
NODE *node;
node=((NODE *)malloc(sizeof(NODE)));
printf("Enter the data:\n");
scanf("%d",&node->data);
node->next=NULL;
if(start==NULL)
{
ptr=start=node;
}
else
{
ptr=node->next;
ptr=node;
}
ptr->next=NULL;
}
create(x-1);
}
void display()
{
NODE *ds;
ds=start;
while(ds!=NULL)
{
printf("%d->",ds->data);
ds=ds->next;
}
}
I think the problem is when i call create(x-1);, but I am not sure.
Is my logic correct? Can someone pin-point my mistake?
Try changing the logic,
int create(int x) {
if (x == 0)
return 0;
else {
NODE *node;
node = ((NODE *) malloc(sizeof (NODE)));
printf("Enter the data:\n");
scanf("%d", &node->data);
node->next = NULL;
if (start == NULL) {
ptr = start = node;
} else {
//ptr = node->next;
ptr->next = node;
ptr = node;
}
ptr->next = NULL;
}
create(x - 1);
}
You are not resetting the head correctly.
Also good to check this implemetation out > http://geeksquiz.com/linked-list-set-1-introduction/
The significant error leading to your problem was your assignment of pointers in create(int). You were assigning the first pointer correctly, but then assigning NULL to all remaining pointers. There are several ways to handle this, but a clean and straightforward way is to only advance ptr=ptr->next within the else block as follows:
if (start == NULL)
{
ptr = start = node;
}
else
{
ptr->next = node;
ptr = ptr->next;
}
You are dynamically allocating memory, so this means you are responsible for tracking its use, preserving a pointer to the starting block of each allocation, and finally freeing the memory when it is no longer in use. Start now. Get in the habit of handling your memory cleanup whenever you allocate, and don't simply rely on the program exit to do it for you. While it may seem trivial now, when you begin handling functions with multiple allocations, etc., if you have not developed good habits in this regard, your code will likely leak memory like a sieve. A simple cleanup function could be nothing more than:
void destroy()
{
if (!start) return;
NODE *ds = start;
while (ds != NULL)
{
NODE *victim = ds;
ds = ds->next;
free (victim);
}
}
The malloc issue. malloc returns the starting address for the block of memory allocated, there is no need to cast the return in C. When you are allocating memory for data types you have just declared, use the variable with sizeof instead of the datatype. e.g.:
NODE *node;
node = malloc (sizeof *node);
instead of
node = malloc (sizeof (NODE));
This will become apparent when dealing with pointers to pointers, etc. It makes far more sense to operate on your variable than it does to remember whether you are allocating for NODE* or NODE**. This is especially true when the allocation is many lines below the declaration in your code or when receiving the pointer in a function argument list.
Additionally, you need to validate the return from malloc each time you allocate memory to insure you haven't exhausted the available memory. e.g.:
NODE *node;
if (!(node = malloc (sizeof *node))) {
fprintf (stderr, "error: virtual memory exhausted\n");
exit (EXIT_FAILURE);
}
Finally, putting it all together, one approach to your problem would be:
#include <stdio.h>
#include <stdlib.h> /* for exit & EXIT_FAILURE */
typedef struct node NODE;
struct node {
int data;
struct node *next;
} *start=NULL,*ptr;
void display();
void create (int);
void destroy();
int main (void)
{
int n;
printf ("\nEnter the no of node: ");
scanf ("%d",&n);
create (n);
display();
destroy();
return 0;
}
void create (int x)
{
if (x == 0) return;
NODE *node;
if (!(node = malloc (sizeof *node))) {
fprintf (stderr, "error: virtual memory exhausted\n");
exit (EXIT_FAILURE);
}
printf ("Enter the data: ");
scanf ("%d",&node->data);
node->next = NULL;
if (start == NULL)
{
ptr = start = node;
}
else
{
ptr->next = node;
ptr = ptr->next;
}
create (x-1);
}
void display()
{
if (!start) return;
NODE *ds = start;
while (ds != NULL)
{
if (ds == start)
printf ("%d", ds->data);
else
printf("->%d", ds->data);
ds = ds->next;
}
printf ("\n");
}
void destroy()
{
if (!start) return;
NODE *ds = start;
while (ds != NULL)
{
NODE *victim = ds;
ds = ds->next;
free (victim);
}
}
Example
$ ./bin/llrecurse
Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8
Use a Memory Checker
Regardless of your platform, it is good to use a memory checker, like valgrind on Linux to check for memory errors and insure you have freed all the memory you have allocated. A memory checker, not only provides a confirmation that all memory has been freed, it will also report on subtle errors in the way you attempt to access the memory you have allocated which can alert you to issues that can bite you later. It is simple to use, simply:
$ valgrind ./bin/llrecurse
==17434== Memcheck, a memory error detector
==17434== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==17434== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17434== Command: ./bin/llrecurse
==17434==
Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8
==17434==
==17434== HEAP SUMMARY:
==17434== in use at exit: 0 bytes in 0 blocks
==17434== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==17434==
==17434== All heap blocks were freed -- no leaks are possible
==17434==
==17434== For counts of detected and suppressed errors, rerun with: -v
==17434== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
That should get you started, and if you learn the good habits early, managing memory will be a whole lot easier as you get further into programming in C.
When you're doing this:
ptr=node->next;
ptr=node;
You're loosing your reference to the tail of the list, and therefore not adding node to the list. You should be doing this:
ptr->next = node;
ptr = ptr->next;
This points the next pointer of the current tail to the new node, then moves ptr down to the new tail.
Also, the ptr->next=NULL at the end of the loop is unnecessary, since ptr is now the same as node, and you already did node->next = NULL.
Here is a method
typedef struct Node {
int data;
struct Node *pNext;
} Node;
Write a mkNode to handle malloc
Node *mkNode(int value, Node *pNext) {
Node *pNode = malloc(sizeof(Node));
if (pNode == NULL) {
printf("error");
exit(-1);
}
pNode->data = value;
pNode->pNext = pNext;
return pNode;
};
create linked list
Node *rec_create_list_from_arr(int *arr, int len, int i) {
if (i == len) {
return NULL;
}
return mkNode(arr[i], rec_create_list_from_arr(arr, len, i + 1));
}
free
void freeList(struct Node *head) {
if (head != NULL) {
freeList(head->pNext);
free(head);
}
}
test
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Node *l = rec_create_list_from_arr(arr, 9, 0);
freeList(l);
return 0;
}
valgrind says it's ok
❯ valgrind --leak-check=full --show-leak-kinds=all ./tmp
==630325== Memcheck, a memory error detector
==630325== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==630325== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==630325== Command: ./tmp
==630325==
123456789
1233456789
1233456789
==630325==
==630325== HEAP SUMMARY:
==630325== in use at exit: 0 bytes in 0 blocks
==630325== total heap usage: 11 allocs, 11 frees, 1,184 bytes allocated
==630325==
==630325== All heap blocks were freed -- no leaks are possible
==630325==
==630325== For lists of detected and suppressed errors, rerun with: -s
==630325== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Is valgrind not finding memory leaks?

This code creates a BST, fills it, and makes an effort to release resources. Two versions of release() are shown below:
typedef struct Node {
int d;
struct Node *left;
struct Node *right;
} Node;
int main() {
Node **tree = NULL;
tree = mkTree();
if (!tree) {
puts("problem\n");
return 1;
}
insert(7, tree);
insert(3, tree);
insert(9, tree);
insert(6, tree);
printTree(*tree);
release(tree);
free(tree);
return 0;
}
/* Make a new binary tree */
Node **mkTree() {
Node **t = malloc(sizeof **t);
return t;
}
/* insert datum d into tree */
bool insert(int d, Node **tree) {
Node *newptr = NULL;
if (tree == NULL) { /*ptr to rootptr NULL */
return false;
}
if (*tree == NULL) {
newptr = buildNode(d);
if (!newptr) {
return false;
}
*tree = newptr;
return true;
}
return insert(d, d < (*tree)->d ? &(*tree)->left : &(*tree)->right);
}
What I don't understand is why valgrind claims all resources are freed in BOTH cases (I and II) below. I try to clear each node using release(), and, at the end of main, I call free(tree) to clear Node **tree, which is declared in main.
I.
/* release resources by passing Node **tree */
void release(Node **tree) {
if (*tree) {
Node *here = *tree;
release(&here->left);
release(&here->right);
}
free(*tree);
}
II.
/* passing Node *tree. this shouldn't free anything, right? */
void release(Node *tree) {
if (tree) {
Node *here = tree;
release(here->left);
release(here->right);
}
free(tree);
}
Despite the choice, running this program with four insertions gives
==5182== HEAP SUMMARY:
==5182== in use at exit: 0 bytes in 0 blocks
==5182== total heap usage: 5 allocs, 5 frees, 60 bytes allocated
What's happening here? Is valgrind just keeping a tally count of the number of malloc's and free's?
Both versions of Release are doing the same thing. One just has an extra (and unnecessary) level of indirection. You can pass a pointer to a function and free that pointer; it is not necessary to pass the address of the variable holding the pointer.
In fact, the call to free does exactly that. It just accepts the pointer value (not the address of the variable holding the pointer).

Resources