Simple stack program in C - c

I am in an OS class and I have to write a simple stack program (the main function just determines what the user is asking you to do). If this were not required to be in C, I would have had this done ages ago, but because I am not very good at C coding, it has "a bug"... The bug so far is that it just continues to "pop" the same value off. (It's not actually popping anything off). I think it's because I don't understand how structures and pointers really work. Or is it a not so obvious coding mistake?
#include <stdio.h>
struct node {
int data;
struct node *next;
struct node *prev;
} first;
void push(int);
void pop();
int main(void)
{
int command = 0;
while (command != 3)
{
printf("Enter your choice:\n1) Push integer\n2) Pop Integer\n3) Quit.\n");
scanf("%d",&command);
if (command == 1)
{
// push
int num;
scanf("%d",&num);
push(num);
}
else
{
if (command == 2)
{
pop();
}
else
{
if (command != 3)
{
printf("Command not understood.\n");
}
}
}
}
return 0;
}
void push (int x)
{
struct node newNode;
newNode.data = x;
newNode.prev = NULL;
newNode.next = &first;
first = newNode;
printf("%d was pushed onto the stack.\n", first.data);
}
void pop()
{
if (first.data == '\0')
{
printf("Error: Stack Empty.\n");
return;
}
printf("%d was popped off the stack.\n", first.data);
first = *(first.next);
first.prev = NULL;
}

first should be a pointer. change it to struct node *first;
in main initialize first=NULL;
change you push/pop operations as below,
void push (int x)
{
struct node *newNode;// It should be a pointer
newNode = (struct node *)malloc(sizeof(struct node));
newNode->data = x;
//newNode.prev = NULL; // You don't need this
newNode->next = first;
first = newNode;
printf("%d was pushed onto the stack.\n", first->data);
}
void pop()
{
struct node *prevPtr;
//if (first.data == '\0')
if (first == NULL) // check if stack is empty
{
printf("Error: Stack Empty.\n");
return;
}
printf("%d was popped off the stack.\n", first->data);
prevPtr = first;
first = first->next;
free(prevPtr);
}

The problem is that first is a single global node, and it's the only node you ever have (aside from a temporary local node inside your call to push).
This line:
first = newNode;
just copies the contents of newNode over into first; and since newNode.next is pointing to first, this means that now first.next is pointing to first, so you have a single-element circular linked list.
Similarly, this line:
first = *(first.next);
just copies the contents of *(first.next) over into first; which is a no-op, since (due to the above), *(first.next) is first.
To solve this problem, you actually need to dynamically create nodes, using malloc (and free). And your global first variable should be a pointer — a node * — that always points to the top element of the stack. (Better yet, your push and pop functions should take first as an argument, rather than having this as a global variable. There's no need for these functions to only allow a single stack to exist.)

What's the value of &first? Hint, it's always the same since first is statically allocated. Even if you change the contents of the structure, the address won't change. This might tell you why there's a bug in push. You'll need to use malloc and free if you are going to have a structure of varying size.

When you have to manage memory yourself, as C requires you to do, you need to know the difference between areas of memory known as the stack and the heap. (This "stack" is slightly different than the data structure you are creating in your program.)
Your push() function is creating a new node on the stack; when the function exits the stack is popped and the memory occupied by your new node is up for grabs. The fact that you see values you entered is due to the fact that your program is very simple. If it was calling other functions that did other things they would almost certainly overwrite that part of the stack and when you called pop(), you would see garbage.
As others have indicated, you need to use the functions malloc() and free(), which give you memory from the heap instead of the stack.

If you want to make a stack with a linked list, make first variable as a pointer. then, when you push a new node to the stack, make a new node by allocating on the heap memory by malloc(). I know that you intend to use it to point to the top of the stack. right?
In your code, first variable is overwritten by a new node since it is not a pointer variable but a value variable. That makes a result to lost a top node of the stack.

void pop()
{
struct node *prevPtr;
//if (first.data == '\0')
if (first == NULL)
{
printf("Error: Stack Empty.\n");
return;
}
printf("%d was popped off the stack.\n", first->data);
prevPtr = first;
first = first->next;
free(prevPtr);
}

#include<stdio.h>
# define max 10
int stack[max],top=-1,size=0;
void push()
{
if(top==(max-1))
{
printf("stack full\n");
}
else
{
top++;
printf("enter the value which you want to insert\n");
scanf("%d",&stack[top]);
}
}
void pop()
{
int str;
if(top==-1)
{
printf("stack empty\n");
}
else
{
str=stack[top];
top--;
printf("the removed element is %d\n",str);
}
}
void display()
{
int i;
for(i=0;i<top;i++)
{
printf("%d\n",stack[i]);
}
}
void main()
{
int enter,x;
do
{
printf("enter 1 for push the element in the array\n");
printf("enter 2 for pop the element in the array\n");
printf("enter 3 for display the element in the array\n");
scanf("%d",&enter);
switch(enter)
{
case 1:push();
break;
case 2:pop();
break;
case 3:display();
break;
default:
printf("invalid syntax");
}
printf("for continue press 0\n");
scanf("%d",&x);
}
while(x==0);
}

Related

Problem deleting the only node from a linked list

I am trying to create a function to delete a certain node if its value matches the value entered by the user. I created a case if there is only a single node, but after deleting the node with free(curr_node) and calling traverse function, the cmd prints out numbers endlessly. What am I missing?
typedef struct Node {
int data;
struct Node *next;
}Node;
Node *head = NULL;
int node_number = 0;
void traverse(Node *head, int count) {
int i = 1;
if(head == NULL) {
printf("No nodes to traverse!");
return;
}
printf("%d node(s), with their respective value: \n", count);
while(head != NULL) {
if(i == count)
printf("%d\n", head->data);
else
printf("%d-", head->data);
head = head->next;
i++;
}
}
void delete_item(Node *head) {
Node *curr_node = head;
int value;
printf("Enter value to search by: ");
scanf("%d", &value);
while(curr_node != NULL) {
if(curr_node->data == value) {
if(curr_node->next == NULL) {
free(curr_node);
head = NULL;
printf("Node deleted successfully!\n");
return;
}
}
//curr_node = curr_node->next;
}
}
Node *create_item() {
Node *result = NULL;
result = (Node *)malloc(sizeof(Node));
if(result == NULL) {
printf("Couldn't allocate memory!");
return 0;
}
printf("Value of node %d: ", node_number + 1);
scanf("%d", &result->data);
result->next = NULL;
node_number++;
return result;
}
int main() {
int nodes;
Node *temp;
head = create_item();
delete_item(head);
traverse(head, node_number);
return 0;
The change to head is not captured by the caller. The fact is, head is actually a local variable to delete_node, and any changes to it (not to be confused with changed through it using deference operations), are not being captured by the caller.
All function arguments in C are by-value. Some will say "that's not true for arrays"; they're wrong. Used in an expression, the "value" of an array is defined by the language standard as a temporary pointer referring to the address of the first element. I.e. still by-value, its just the value isn't what you may expect. But in your case, head is by value. If you had a function void foo(int x) you already know that modifying x within foo does not change the caller's int they passed; the same is true here. Just because its a pointer makes no difference. If you want to modify a caller-argument you have to build the road to get there.
There are two general schools around this.
Use a pointer to pointer argument and pass the address of head in main. This requires deference of the pointer-to-pointer to get the actual list head, but also allows you to modify the callers pointer.
Use the return result of the function to communicate the current list head back to the caller (i.e. the head after whatever operation is being performed.
The first is more complicated, but allows you to use the return result for other purposes (like error checking, hint). The latter is easier to implement. Both will accomplish what you want. The former is shown below:
void delete_item(Node **head)
{
int value;
printf("Enter value to search by: ");
if (scanf("%d", &value) == 1)
{
while (*head)
{
if ((*head)->data == value)
{
void *tmp = *head;
*head = (*head)->next;
free(tmp);
printf("Node deleted successfully!\n");
break;
}
head = &(*head)->next;
}
}
}
The caller, main in this case, needs to be modified as well:
delete_item(&head); // <== note passed by address now.

creating temp stack to print it in c

current uni student and i have been tasked with creating a stack using the following structure
typedef char stackitem;
struct stack {
stackitem d;
struct stack *next;
};
typedef struct stack ELEMENT;
typedef ELEMENT *POINTER;
I am having issues with printing my stack. What i am trying to do is create a temp stack where I print the element and then pop it off. however it seems to be removing it from the original stack which I dont want.
here is the code:
void print_stack(POINTER Top)
/*Print the contents of the stack. Do not modify the stack in any way. */
{
POINTER temp = Top;
printf("Start printing the stack ...\n");
while (temp != NULL){
printf("%c\n",temp->d);
pop(&temp);
}
}
void pop(POINTER *Top)
/* Remove the top item */
{
POINTER Top1 = *Top;
if (Top != NULL)
{
*Top = Top1->next;
// printf("Remove element %c\n", Top1->d);
free(Top1);
}
else
printf("Empty stack.\n");
}
In my mind I am printing and popping from the temp pointer which shouldn't affect the original pointer top but when i insert into the stack and print it the first time it prints correctly and then the second time it prints nothing.
this is my main
POINTER top;
top= (POINTER) NULL;
stackitem A='A';
stackitem B='B';
push(&top,A);
push(&top,B);
print_stack(top); // prints B A
print_stack(top); // prints nothing
Any help with what is going wrong?
Your print_stack() method currently looks like this:
void print_stack(POINTER Top) {
POINTER temp = Top;
printf("Start printing the stack ...\n");
while (temp != NULL){
printf("%c\n",temp->d);
pop(&temp); // Calling `pop()` will modify your Stack
}
}
You're calling pop() in your loop which modifies the stack; which is not good since print_stack is a read operation and should not be modifying the list. You can instead just increment the pointer so that it points to next value:
void print_stack(POINTER Top) {
POINTER temp = Top;
printf("Start printing the stack ...\n");
while (temp != NULL){
printf("%c\n",temp->d);
temp = temp->next; // Go to next element of stack
}
}
I tested this code(I just needed to add additional push and createNewStackNode methods that weren't present:
// ...
POINTER createNewStackNode(stackitem i) {
POINTER newNode = (POINTER) malloc(sizeof(ELEMENT));
newNode->d = i;
newNode->next = NULL;
return newNode;
}
void push(POINTER *top, char item) {
POINTER curr = createNewStackNode(item);
curr->next = *top;
*top = curr;
}
// ...
int main() {
POINTER top;
top= (POINTER) NULL;
stackitem A='A';
stackitem B='B';
push(&top,A);
push(&top,B);
print_stack(top); // prints B A
push(&top, 'C');
push(&top, 'D');
push(&top, 'E');
push(&top, 'F');
print_stack(top);
}
This prints the following output:
Start printing the stack ...
B
A
Start printing the stack ...
F
E
D
C
B
A
As another user suggested, you don't create a second stack rather you just create a second pointer that shows you the same memory position as the original stack.
If I was you I would try to add the stack into an array (you can search for guidance here) and then modify that array. That way your original stack will be unharmed.
The print_stack function claims it doesn't modify the stack, but it does. For example, it calls pop which calls free, destroying the object on the top of the stack.

passing top pointer of stack as argument

My problem is based on pointers, I want to know how can i pass top of stack in function printStack() so that i can access all nodes of stack.I am storing elements in array and same time pushing into stack.
here in this code when i execute it does not print anything.
here my code
#include<stdio.h>
struct stack
{
int data;
struct stack *next;
};
typedef struct stack s;
s *top=NULL,*neu;
//push data into stack
void push(int data)
{
neu = (s *)malloc(sizeof(s));
neu->data= data;
neu->next = NULL;
if(!top)
{
neu=top;
}
else
{
neu->next = top;
top = neu;
}
}
//pop data and move top to top->next
void pop()
{
s *temp = top;
top = top->next;
free(top);
}
//print data present in stack
void printStack(s *top)
{
while(top)
{
printf("%d ",top->data);
pop();
}
}
int main()
{
int i=0,A[3],d;
for(i=0;i<3;i++)
{
scanf("%d",&A[i]);
push(A[i]);
}
printStack(top);
return 0;
}
So there are 3 problems:-
You are freeing top rather than temp in pop().
You are changing to the local variable passed in printStack.
Simply call this printSack(); having function signature void printStack().
Also when creating the nodes
if(!top)
{
neu=top;
^^^^
}
This will be top=neu;
Some things that you should learn to do:-
Use debugger. Learn how to use it.
Don't cast the return value of malloc.
Check the return value of malloc and scanf.
You have used too many global variables - code that involves lots of global variables are tend to be difficult to debug. You could easily avoid it here.
For example:-
if( scanf("%d",&A[i])!= 1){
fprintf(stderr,"Error in input");
exit(EXIT_FAILURE);
}
In case of malloc
neu = malloc(sizeof(s));
if(neu == NULL ){
perror("Malloc failed");
exit(EXIT_FAILURE);
}
The main thing is - your code is doing nothing basically. It is even useless to create those methods which are so closely couped with each other with data. We use functions so that code becomes modular and each of the function should be reusable.( Atleast to some extent). Here you have missed that part.
You have a simple error here:
void pop()
{
s *temp = top;
top = top->next;
free(top);
}
Rather than freeing Top, you likely meant to free(temp);
Additionally, consider developing good habits early. Don't cast the return of malloc() in C. Also, don't assume that malloc() worked; check to see if it returns something other than NULL.

Global linked list pointing to NULL when passed through a function

I am facing this issue, in which if I am passing a linked list (which I defined as global) through a function (to insert a node), I am always getting a NULL value once the pointer returned to main function.
However, if I am adding the node to the global defined, it is working fine which is expected too. Can someone please help me why this piece of code didn't work and *list always points to NULL
struct node{
int val;
struct node *next;
};
typedef struct node node;
static node *list=NULL;
boolean add_node(node *list, int n, int val)
{
node *temp=NULL;
temp = (node *)malloc(sizeof(node));
temp->val = val;
temp->next = NULL;
if((list==NULL) && (n!=0))
{
printf("link list is NULL and addition at non zero index !");
return (FALSE);
}
if(list==NULL)
{
printf("list is NULL ");
list= temp;
}
else if(n==0)
{
temp-> next = list;
list=temp;
}
else
{
node *temp2;
temp2 = list;
int count =0;
while(count++ != (n-1))
{
temp2 = temp2->next;
if(temp2==NULL)
{
printf("nth index %d is more then the length of link list %d ",n,count);
return (FALSE);
}
}
node *temp3;
temp3 = temp2->next;
temp2-> next = temp;
temp->next = temp3;
}
printf("List after node insertion \n");
print_link_list(list);
return (TRUE);
}
main()
{
c= getchar();
switch(c)
{
case 'I':
{
printf("Insert a index and value \n");
int index,value;
scanf_s("%d",&index);
scanf_s("%d",&value);
if(add_node(list,index,value)==FALSE)
{
printf("Couldn't add the node \n");
}
if(list==NULL)
{
printf("\n After Insert op.,list is NULL, add %x",list);
}
else
{
printf("After Inset op., list is not Null, add %x",list);
}
}
break;
case 'D':
....
}
The global variable list is never modified, only the parameter list.
You probably want that parameter to be a pointer to a pointer, and assign through, instead of to, the parameter.
Try changing the function definition to use a pointer to a pointer:
boolean add_node(node **list, int n, int val)
You need to do this because your global variable list needs to be updated. The global is a pointer: an address. In your add_node function when you say list = temp you are only modifying the local pointer (also named list). When you leave the function the global list remains unchanged. However, if you pass a pointer to that global pointer (the pointer to a pointer) you are then able to modify the address stored in the original pointer.
An example:
int *pGlobal = NULL;
void someThing(int *pInt)
{
int LocalInt = 3;
pInt = &LocalInt; // I can change where this pointer is pointing - it's just a copy
// pGlobal remains unchanged
}
void someThingElse(int **ppInt)
{
// I am now modifying the ADDRESS of a pointer that we have the address of
*ppInt = malloc(sizeof(int));
// pGlobal has been changed to point at my allocated memory
}
void main()
{
// This passes a COPY of the address held in pGlobal
someThing(pGlobal);
// Here we are now passing a pointer (address) TO another pointer.
// The pointer pGlobal does occupy some real space in memory. We are passing a
// COPY of the value of its location so we can modify it.
someThingElse(&pGlobal);
}
Also, for good practice, don't name a global the same as a local variable (list) or parameter - it'll compile but can easily cause problems/confusion/bugs!

Single linked list

I have created a single linked list. Everything works fine.
I just want to know if I have done anything potentially dangerous in my code. The code snippets I am concerned about is my push, pop, and clean-up. The parts of the code is just for user interaction so not really important (I posted anyway so that it was more clear in what I was doing). Just the linked list application.
Many thanks for any suggestions, as this is my fist attempt.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct product_data product_data_t;
struct product_data
{
int product_code;
char product_name[128];
int product_cost;
product_data_t *next;
};
static product_data_t *head = NULL;
static product_data_t *tail = NULL;
static product_data_t *new_product = NULL;
// Push a product on to the list.
void push(int code, char name[], int cost);
// Pop (delete) a product from the list.
void pop(int code);
// Display all product in the list.
void display_list();
// Delete all memory allocated on the list
void clean_up();
// Display menu
void menu();
int main(void)
{
menu();
getchar();
return 0;
}
void push(int code, char name[], int cost)
{
// Allocate memory for the new product
new_product = calloc(1, sizeof(product_data_t));
if(!new_product)
{
fprintf(stderr, "Cannot allocated memory");
exit(1);
}
/* Populate new products elements fields */
new_product->product_code = code;
strncpy(new_product->product_name, name, sizeof(new_product->product_name));
new_product->product_cost = cost;
new_product->next = NULL;
// Set the head and tail of the linked list
if(head == NULL)
{
// First and only product
head = new_product;
}
else
{
tail->next = new_product;
}
tail = new_product;
}
// Find the product by code and delete
void pop(int code)
{
product_data_t *product = head;
product_data_t *temp = NULL;
product_data_t *previous = head;
int found = 0; // 0 - Not Found, 1 - Found
if(!head)
{
puts("The list is empty");
return;
}
while(product)
{
if(product->product_code == code)
{
found = 1; // Found
// Check if this is in the first node - deleting from head
if(head->product_code == code)
{
temp = head;
head = head->next;
free(temp);
// Finished Deleting product
return;
}
// Check if this is the end node - deleting from the tail
if(tail->product_code == code)
{
temp = tail;
tail = previous;
free(temp);
// Finished deleting product
return;
}
// delete from list if not a head or tail
temp = product;
previous->next = product->next;
free(temp);
// Finished deleting product
return;
}
// Get the address of the previous pointer.
previous = product;
product = product->next;
}
if(!found)
{
printf("code [ %d ] was not found\n", code);
}
// Set all to null after finished with them
product = NULL;
temp = NULL;
previous = NULL;
}
// Traverse the linked list
void display_list()
{
// Start at the beginning
product_data_t *product = head;
while(product)
{
printf("===================================\n");
printf("Product code: \t\t%d\n", product->product_code);
printf("Product name: \t\t%s\n", product->product_name);
printf("product cost (USD): \t%d\n", product->product_cost);
printf("===================================\n\n");
// Point to the next product
product = product->next;
}
// Finished set to null
product = NULL;
}
// Release all resources
void clean_up()
{
product_data_t *temp = NULL;
while(head)
{
temp = head;
head = head->next;
free(temp);
}
head = NULL;
temp = NULL;
// End program - goodbye
exit(0);
}
void menu()
{
int choice = 0, code = 0, cost = 0;
char name[128] = {0};
do
{
fflush(stdin); // Flush the input buffer
puts("========= Welecome to linked list ===============");
puts("[1] Add new product to the list");
puts("[2] Delete a product from the list");
puts("[3] Display all products");
puts("[4] Exit and clean up");
printf("Enter your choice: ");
scanf("%d", &choice);
switch(choice)
{
case 1:
printf("Enter product code: ");
scanf("%d", &code);
printf("Enter cost: ");
scanf("%d", &cost);
printf("Enter name: ");
scanf("%s", name);
push(code, name, cost);
break;
case 2:
printf("Enter product code: ");
scanf("%d", &code);
pop(code);
break;
case 3:
display_list();
break;
case 4:
clean_up();
break;
default:
puts("Incorrect choice");
break;
}
}while(choice != 4);
}
From pop()
if(head->product_code == code)
{
temp = head;
head = head->next;
free(temp);
// Finished Deleting product
return;
}
In the case of there only being one item, 'head' and 'tail' would be pointing to the same node. However, if you pop this one item, 'head' will be adjusted but 'tail' will still be pointing to the free'd node. This will leave a bad pointer, which may cause your computer to explode.
Addendum: Similarly, 'new_product' will be dangling if you ever pop the last node that was pushed, and clean_up() will leave the 'tail' pointer dangling as well. Even if the code sample provided will never dereference these after they're free'd, dangling pointers in C code should always be treated as "potentially dangerous".
strncpy(new_product->product_name, name, sizeof(new_product->product_name));
if the string is longer than the size you have it won't be terminated correctly.
I see no reason why new_product should be global and every reason why it should not be.
It looks like you're on the right track, but there are issues. I would remove the global variables, and instead have a list_t struct (containing head and tail) that you pass into functions. As others have noted, you may also want to make the list generic by using (e.g.) a node_t type and void* data pointer.
Generally push and pop are used to refer to adding or removing an item at the beginning, not an arbitrary location (as you do); this is just a question of naming.
If you had product_name char *product_name instead, that would allow you to remove the length limitation as well as the need for strncpy. You would just have the caller allocate the string, and then free it in clean_up.
You could consider using a enum to improve your menu's readability. For "Check if this is in the first node - deleting from head" (same for tail), you should just compare head to product, not compare the codes.
After "tail = previous", you should set tail->next to NULL.
Agree with the issues raised by goldPseudo and thaggie/Steven.
In push(), replace strncpy() with strlcpy() to ensure the destination string is always NUL terminated.
In cleanup(), I'd suggest that you remove the exit(0); statement -- you don't need it. Exiting a programme from within a subroutine is generally not the best thing to do.
You should take away one lesson from creating your first singly linked list, and that is, singly linked lists are generally not very useful in the real world because:
They're too hard to manipulate. Just look at the complexity of your pop() subroutine.
Relatively slow because you have to start at the beginning of the list each time you want to retrieve an element from the list.
You should now attempt to write your first doubly linked list. While doubly linked lists are more complex to implement, they are easier to manipulate (especially when deleting an element) than singly linked lists.
Is there any reason you call exit(0) from clean_up function? I think this is potential dangerous, since you don't give a chance to the user to finish program correctly.
As well I would suggest you to use data encapsulation when you building up you data structure:
typedef struct
{
int product_code;
char product_name[128];
int product_cost;
list_node *next;
} list_node;
typedef struct
{
list_node* head;
list_node* tail;
list_node* current;
int size;
} list;
Also it's a good practice to use trail dummy node at the head of your list to make your code more generic.
Following normal naming convensions, push and pop are related to stacks - i.e. push() should add an item to the top of the stack (you add to the tail of the list, which is fine!), and pop() should return and remove the item from the top of the stack (you search for a named item anywhere in the list and remove it.)
Function names aside, I would suggest a more generic (abstract) implementation of the list, where the content of a node is a pointer to arbitrary data (which in your special case will later be a product_data). This way your linked list can be re-used for any content, and is easier to debug, read and to maintain.
It would also be a better idea not to have stuff global, but rather permit multiple instances of a list. The normal C way is to keep the data in a struct, and then to pass an instance as first argument to each function.

Resources