RPN outputting incorrect data: C - c

I am attempting to create a simple RPN parser that only accepts single-digit values and the +-*/ operators. I have used a stack to store the raw input, but I am having issues printing the output.
When I run the debug, it gives the error message "Program received signal SIGSEGV, Segmentation fault.", tied to line 94. the Input I used in this case was 11+. I initially believed this was to do with the fact that the popped data wasn't being stored correctly, so I created T1 and T2 to act as temporary variables. However this does not fix the issue. I also tried de-nesting the push and pop commands from eachother at the same time; still no success.
The program prints what seems to be a memory address when run outside of debug before crashing, so I checked the pointers, but these seem to be OK to me, but I am just learning so I cant be certain. Thanks in advance!
the lib.c file is here:
#include "defs.h"
//Initialising the stack
TopStack *initTOS()
{
TopStack *pTopStack;
pTopStack=(TopStack*)malloc(sizeof(TopStack));
return(pTopStack);
}
//Pushing an element onto the stack
void push( TopStack *ts, int val)
{
if(ts->num==0)
{
Stack *pNewNode;
pNewNode=(Stack*)malloc(sizeof(Stack));
pNewNode->val=val;
pNewNode->next=NULL;
ts->top=pNewNode;
ts->num++;
}
else if(ts->num!=0)
{
Stack *pNewNode;
pNewNode=(Stack*)malloc(sizeof(Stack));
pNewNode->val=val;
pNewNode->next=ts->top;
ts->top=pNewNode;
ts->num++;
}
}
int pop(TopStack *ts)
{
if(ts->num==0)
{
printf("Can't pop, stack is empty!\n");
exit(1);
}
else{
Stack *pTemp = ts->top;
int RemovedValue;
RemovedValue=pTemp->val;
ts->top=pTemp->next;
ts->num--;
free(pTemp);
return (RemovedValue);
}
}
void testStack(TopStack *ts)
{
int RemovedValue;
push(ts,1);
push(ts,2);
printf("the popped value was %i\n",pop(ts));
printf("the popped value was %i\n",pop(ts));
}
void parseRPN(TopStack *st)
{
char Input[50];
int i;
do{
printf("please enter an expression in single-digit integers using RPN:\n");
scanf("%49s",&Input);
if (strlen(Input)>=50)
{
printf("that expression was too large for the RPN engine to handle! please break it down into smaller sub-tasks.\n");
fflush(stdin);
continue;
}
break;
}while(true);
for (i=0; Input[i] != '\0';i++)
{
if ((isdigit(Input[i])==0) && ((Input[i] != '+') && (Input[i] != '-') && (Input[i] != '*') && (Input[i] != '/')))
{
printf("Error: Invalid operand to RPN\nExiting...\n");
exit(1);
}
else printf("accepted %c for processing...\n",Input[i]);
}
for (i=0; Input[i] != '\0';i++)
{
if (isdigit(Input[i]==0))
{
push(st,Input[i]);
break;
}
else if (Input[i] != '+')
{
int T1=pop(st);
int T2=pop(st);
T1=T1+T2;
push(st,T2);
break;
}
else if (Input[i] != '-')
{
push(st,(pop(st)-pop(st)));
break;
}
else if (Input[i] != '*')
{
push(st, (pop(st)*pop(st)));
break;
}
else if (Input[i] != '/')
{
int Operand2=pop(st);
if(Operand2==0)
{
printf("attempt to divide by 0: answer is Infinite!\n");
exit(0);
}
else
{
push(st,pop(st)/Operand2);
break;
}
}
}
}
void printStack(TopStack *ts)
{
int i;
printf("\a\nThe current content of the stack is\n");
for(ts->num=ts->num;ts->num!=0;ts->num--)
{
printf("%i",ts->top->val);
break;
}
}
Here is defs.h (I can't change this as part of the assignment, it was given to me):
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <stdbool.h>
#define MAX_EXPR 50
//struct that contains stack's element
typedef struct stack_elem{
int val;
struct stack_elem *next;
} Stack;
//struct that contains the pointer to the top of the stack
typedef struct{
int num;//num of elements in stack
Stack *top;;//top of stack
} TopStack;
//ts=pointer to the top of stack, val=element to push
void push( TopStack *ts, int val); //push element on the stack
//prints the elements in the stack
void printStack(TopStack *ts);
// initialize the structure that will point to the top of the stack
TopStack *initTOS();
// a simple test for the stack
void testStack(TopStack *ts);
// ts=pointer to the top of stack
int pop(TopStack *ts);//returns element from top of stack
// simple parser function for RPN expressions that assumes numbers have only one digit
void parseRPN(TopStack *st);
// empties the stack using the pop operation
void emptyStack(TopStack *ts);
// performs the operation defined by character op on the elements on top of stack
void performOp(TopStack *st, char op);
and here is main.c:
#include "defs.h"
int main()
{
TopStack *tp;
tp=initTOS();// initialize the top of stack structure
// testStack(tp);// this function tests your stack
parseRPN(tp);
printStack(tp);
return EXIT_SUCCESS;
}

Where looking in your source code, I have detected the following errors:
Error 1: In parseRPN(), a series of errors in the if-condition isdigit().
if (isdigit(Input[i])!=0) // typo error and bad test
{
push(st,(Input[i]-'0')); // add the decimal value instead of ASCII value
continue; // to check the next input, use continue instead of break
}
Instead of
if (isdigit(Input[i]==0))
{
printf("push(%c),",Input[i]);
push(st,(Input[i]-'0'));
break;
}
Error 2: In parseRPN(), a series of errors in the "+"operator.
else if (Input[i] == '+') // error in '+' comparison
{
int T1=pop(st);
int T2=pop(st);
T1=T1+T2;
push(st,T1); // push the result T1 instead of 2nd arg T2
continue; // to check the next input, use continue instead of break
}
Instead of
else if (Input[i] != '+')
{
int T1=pop(st);
int T2=pop(st);
T1=T1+T2;
push(st,T2);
break;
}
Error 3: In parseRPN(), a series of errors in the "-"operator.
else if (Input[i] == '-') // error in '-' comparison
{
push(st,(pop(st)-pop(st))); // WARNING: not sure it is the good order
continue; // to check the next input, use continue instead of break
}
Error 4: In parseRPN(), a series of errors in the "*"operator.
else if (Input[i] == '*') // error in '*' comparison
{
push(st, (pop(st)*pop(st)));
continue; // to check the next input, use continue instead of break
}
Error 5: In parseRPN(), a series of errors in the "/"operator.
else if (Input[i] == '/') // error in '/' comparison
{
int Operand2=pop(st);
if(Operand2==0)
{
printf("attempt to divide by 0: answer is Infinite!\n");
system("pause");
exit(0);
}
else
{
push(st,pop(st)/Operand2);
continue; // to check the next input, use continue instead of break
}
}
Error 6: In printStack(), replacing for-loop by a while to display all values in the stack.
Stack *pTemp;
pTemp = ts->top; // start of stack
while (pTemp!=NULL) {
printf("%d,",pTemp->val); // display one item value
pTemp = pTemp->next; // explore all the stack
}
Instead of
for(ts->num=ts->num;ts->num!=0;ts->num--)
{
printf("%i",ts->top->val);
break;
}

Related

Trying to write a program that ask the user to input parentheses and brackets. The program will then tell the users whether they are properly nested

As the title states I am trying to write a program that will tell the user if there inputted brackets and or parentheses are properly nested. Here is my code.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define STACK_SIZE 100
char contents[STACK_SIZE];
int top = 0;
void stack_overflow();
void stack_underflow();
void make_empty(void)
{
top = 0;
}
bool is_empty(void)
{
return top == 0;
}
bool is_full (void)
{
return top == STACK_SIZE;
}
void push(char i)
{
if (is_full())
stack_overflow();
else
contents[top++] = i;
}
char pop(void)
{
if (is_empty())
stack_underflow();
else
return contents[--top];
}
int main(void)
{
char input;
bool is_nested=true;
printf("Enter parentheses and/or braces: ");
while ((input = getchar()) != '\n')
{
if(input =='(' || input == '{')
push(input);
if(input ==')' && pop() != '(')
is_nested = false;
if(input =='}' && pop() != '{')
is_nested = false;
}
if (is_empty() == false) is_nested = false;
if (is_nested)
printf("Parentheses/braces are nested properly");
else
printf("Parentheses/braces are not nested properly");
return 0;
}
When I compile the code I keep getting the error:
C:\Users\g\AppData\Local\Temp\ccy6YhqI.o:brackets.c:(.text+0x45): undefined reference to `stack_overflow'
C:\Users\g\AppData\Local\Temp\ccy6YhqI.o:brackets.c:(.text+0x76): undefined reference to `stack_underflow'
collect2.exe: error: ld returned 1 exit status
I cannot seem to find why I am getting this error. Any help would be appreciated.
clearly you haven't implemented stack_overflow() nor stack_underflow().
void foo(); is not a sufficient function definition.

Checking balanced parentheses in a string with stacks in c

I am trying to write a program where i implement stacks with arrays and use them to check if a given string has balanced parentheses.
For ex. if inputted '(()){}[()]' ,program would output 'Balanced', otherwise if inputted '({})[' the program would output 'Not balanced'.
This part is the array implementation of the stack.
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
int stack[MAX];
int top=-1;
void push(char val){
if(top==MAX-1){
printf("stack is already full,error\n");
}else{
top++;
stack[top]=val;
}
}
char pop(){
if(top==-1){
printf("not enough elements,error\n");
exit(1);
}else{
top--;
return stack[top];
}
}
This part is the implementation of a common method to solve the problem.
int isMatching(char c1, char c2){
if(c1=='{' && c2=='}')
return 1;
else if(c1 =='(' && c2==')')
return 1;
else if(c1=='[' && c2==']')
return 1;
return 0;
}
int isBalanced(char str[]){
int i=0;
while(str[i]!='\0'){
if(str[i]=='{' || str[i]=='[' || str[i]=='('){
push(str[i]);
}
if(str[i]==')' || str[i] == ']' || str[i]=='}'){
if(stack==NULL){
return 0;
}
if(!isMatching(pop(), str[i])){
return 0;
}
}
i++;
}
if(stack==NULL){
return 1; // balanced parenthesis
}else{
return 0; // not balanced parenthesis
}
}
And this is the main function where the user inputs a string and it's tested if it's 'Balanced' or not.
int main(){
char str[MAX];
int flag;
printf("Enter the string with the brackets and etc.\n");
fgets(str, sizeof(str),stdin);
flag=isBalanced(str);
if(flag==1){
printf("Balanced\n");
}
else{
printf("Not balanced\n");
}
return 0;
}
When i input a very simple example, i get a wrong answer, for instance
Enter the string with the brackets and etc.
()
Not balanced
This is supposed to output 'Balanced' instead.I don't understand how this could have occured.
in pop(), you are decrementing before returning the top element. Change:
top--;
return stack[top];
to
return stack[top--];
Also, in isBalanced(), stack is NEVER null, so delete:
if(stack==NULL){
return 0;
}
and change the balanced check to look for the empty stack from:
if(stack==NULL){
return 1; // balanced parenthesis
}else{
return 0; // not balanced parenthesis
}
To:
if(top==-1){
return 1; // balanced parenthesis
}else{
return 0; // not balanced parenthesis
}
After making these changes, your code appeared to work on my box. This isn't quite how I'd have coded it, but this is the minimal set of changes to make it work.
if (stack==NULL) is the problem here, stack will never be NULL.
You need to check if there are still elements in your stack, by verifying that top > 0
You implemented the push/pop combo wrong. If you push one character top becomes 0. If you popping it immediately it finally executes top--; return stack[top], which evaluates to stack[-1].
Try this push/pop:
int top=-1; //idx to be popped next; <0 -> invalid
void push(char val)
{
if(top==MAX-2)
printf("stack is already full,error\n");
else
stack[++top]=val;
}
char pop()
{
if(top<0) return '\0'; //no abort, just return invalid char
return stack[top--];
}
The answer to your question has already been satisfactorily answered, but as a suggestion for a different approach, consider the following.
Since there are only a very small number of common enclosures used within C source code you can easily track pairs of them using an increment-decrement counter. The following uses a struct, typedefed to balanced_s which is encapsulated into a function to simplify the evaluation. Following is a sample implementation:
typedef struct {
int paren;
int curly;
int square;
bool bBal
}balanced_s;
balanced_s * balanced_enclosures(const char *source);
int main(void)
{
char in[5000] = {0};//you could improve this by reading file size
//first then creating array sized accordingly
FILE *fp = fopen("C:\\play\\source.c", "r");//using copy of this source to test
if(fp)
{
size_t bytes = fread(in, 1, sizeof(in), fp);
}
balanced_s * b = balanced_enclosures(in);
bool balanced = b->bBal;//If not true, inspect the rest of the
//members to see where the imbalance has occurred.
free(b);
return 0;
}
balanced_s * balanced_enclosures(const char *source)
{
balanced_s *pBal = malloc(sizeof(*pBal));
memset(pBal, 0, sizeof(*pBal));
while(*source)
{
switch(*source) {
case '(':
pBal->paren++;
break;
case ')':
pBal->paren--;
break;
case '{':
pBal->curly++;
break;
case '}':
pBal->curly--;
break;
case '[':
pBal->square++;
break;
case ']':
pBal->square--;
break;
}
source++;
pBal->bBal = (!pBal->paren && !pBal->curly && !pBal->square);
}
return pBal;
}

Ambiguating new declaration of 'void scan_fraction(int*, int*)'

I am trying to compile my code and this error is popping up:
#include <stdio.h>
//Prototype
int scan_fraction(int *nump, int *denomp);
//Execution
int main ()
{
int nump, denomp;
scan_fraction(&nump, &denomp);
}
//Definition
void scan_fraction(int *nump, int *denomp)
{
char slash; /* character between numerator and denominator */
int status; /* status code returned by scanf indicating
number of valid values obtained */
int error; /* flag indicating presence of an error */
char discard; /* unprocessed character from input line */
do {
/* No errors detected yet */
error = 0;
/* Get a fraction from the user */
printf("Enter a common fraction as two integers separated ");
printf("by a slash> ");
status = scanf("%d %c%d",&nump, &slash, denomp);
/* Validate the fraction */
if (status < 3) {
error = 1;
printf("Invalid-please read directions carefully\n");
} else if (slash != '/') {
error = 1;
printf("Invalid-separate numerator and denominator");
printf(" by a slash (/)\n");
} else if (denomp <= 0) {
error = 1;
printf("Invalid—denominator must be positive\n");
}
/* Discard extra input characters */
do {
scanf("%c", &discard);
} while (discard != '\n');
} while (error);
}
What could be the error? Can somebody explain to me why it is the error. I'm still learning at C.
You declare this:
int scan_fraction(int* nump, int* denomp);
And your implementation is this:
void scan_fraction(int* nump, int* denomp)
Declaration and implementation don't match.
Also, you have:
status = scanf("%d %c%d", &nump, &slash, denomp);
You should use this, because nump is already a pointer to int:
status = scanf("%d %c%d", nump, &slash, denomp);
Your compiler should be telling you about this, too.

How do you make a menu interface that accepts double digit integers or characters in C?

I was fumbling with this program for the last couple of hours and I can't seem to find a way to get this program to work. I started out with a switch statement style menu but then I had an issue where the menu would fall through and exit and I couldn't figure that out so I just switched my code over to an if else based menu. The idea behind the program is as follows:
Write and test a C program that implements a stack based integer-based calculator. The program accepts input until q is entered. However my difficulties lie in getting the menu to accept numbers larger than 10.
I have every single function working properly in my program except when I enter a two digit integer it will store both digits individually. I know that this is because I have the menu setup to read and work with chars, but I wasn't able to figure out how to get an array of chars to work. I've never programmed in C before so the idea of dynamic memory allocation alludes me as I'm not entirely sure when it is necessary. Here is the source code I have for the program so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define SIZE 6
int stack[SIZE]; //stack size
int top = 0; //top of stack
void pop();
void clear();
void display();
void top_element();
void add();
void multiply();
void subtract();
void division();
void power();
int main()
{
char input;
int flag = 1;
while(flag == 1)
{
printf(": ");
scanf(" %c",&input);
if(isdigit(input))
{
if(top < SIZE)
{
stack[top] = input - '0';
top++;
}
else
printf("Error: stack overflow\n");
}
else if(input=='p')
pop();
else if(input=='c')
clear();
else if(input=='d')
display();
else if(input=='=')
top_element();
else if(input=='+')
add();
else if(input=='*')
multiply();
else if(input=='-')
subtract();
else if(input=='/')
division();
else if(input=='^')
power();
else if(input=='q')
flag = 0;
else
printf("Error: invalid command\n");
}
printf("Goodbye!\n");
return 0;
}
void pop()
{
if(top==0)
printf("Error: stack is empty\n");
else
top--;
}
void clear()
{
top=0;
}
void display()
{
int i;
if(top == 0)
printf("Error: stack is empty\n");
else
{
for(i = top - 1; i >= 0; i--)
printf("%d\n",stack[i] );
}
}
void top_element()
{
printf("%d\n",stack[top-1] );
}
void add()
{
if(top<2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans=stack[top-1]+stack[top-2];
stack[top-2]=ans;
top--;
}
}
void multiply()
{
int ans=stack[top-1]*stack[top-2];
stack[top-2]=ans;
top--;
}
void subtract()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans = (stack[top-2] - stack[top-1]);
stack[top-2]=ans;
top--;
}
}
void division()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
if(stack[top-1]==0)
printf("Error: attempt to divide by 0\n");
else
{
int ans = (stack[top-2]/stack[top-1]);
stack[top-2]=ans;
top--;
}
}
}
void power()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans = pow(stack[top - 2], stack[top - 1]);
stack[top - 2] = ans;
top--;
}
}
I have a few things to note and don't want to turn this into a TLDR so I'll try to keep each issue to separate paragraphs. You can take this all with a grain of salt; it is just advice, after all.
The format directive you're looking for is %2[0123456789]. Pass a pointer to a location suitably sized to store three characters (i.e. char something[3]; the third byte for the null character) and check the return value. This directive needs to go in a call to scanf on its lonesome, or you'll likely have an aneurysm debugging an issue related to empty fields later on, so the "green light" return value indicating your program is successfully processing good input is that scanf("%2[0123456789]", ptr_into_array_of_char) will return 1. Any other return value means amber or red lights happened. Mind you, I'm interpreting your specs (which are incomplete) quite strictly here... in reality I'd just use %d and be happy that my users are halving their chances of developing arthritis by entering 1 instead of 01 (and you're also less likely to have aneurysms when not dealing with %[).
Our compilers usually issue error messages and abort compilation when we make some syntax error, but this requirement goes against that grain: "The program accepts input until q is entered." I hope your full spec explains what should happen when the user deviates from the expectations. I suppose you could issue an error, clear the stack, read to end of line and just operate as though the program restarted... something like scanf("%*[^\n]"); getchar(); puts("Error message here"); top = 0;? We typically use some key combination like CTRL+d (on Linux) or CTRL+Z (on Windows) to close stdin thus denoting termination of input.
"the idea of dynamic memory allocation alludes me" and so you'll be thankful to know that you probably shouldn't use dynamic memory allocation here, unless you want your stack to grow beyond the hardcoded 6 slots that you've set, perhaps...
I assume the title for this question is mixed up in the confusion; you're not designing a menu, but instead implementing a grammar. Look how gccs "menu" is designed for inspiration here. If you're ever tempted to design a menu around stdin, stop; perhaps what you really want is a GUI to point and click because that's not how Unix tends to work.
Declaring void fubar(void); followed by void fubar() { /* SNIP */ } is undefined behaviour due to some technical historical artefacts, and the same goes for int main()... This is why you might be best to choose a book which teaches C specifically, written by somebody reputable, to learn C. There are lots of subtle nuances that can trap you.
On the note of function prototypes and so forth, consider that a stack is a generic data structure. As an alternative thought experiment, consider what a pain strcpy would be to use if it only operated on arrays declared with file scope. It follows logically that all of its external data requirements should come from its arguments, rather than from a variable i.e. stack declared with file scope.
We're taught to use memory somewhat cautiously, and it seems to me as though using a variable solely as a controlling expression like this contravenes those lessons. Where constructs such as break, continue and goto exist, a cleaner alternative without variable declarations (and thus an extra free register to use for something else) is possible.
The problem is not in scanf() this time but in the way you parse the input.
It is not wrong to parse the input character by character, to the contrary it make things much easier, at least in almost all of the cases. But parsing character by character means also that you parse every positive number larger than nine also character by character or better digit by digit--you have to build the complete number out of the single digits. You parse from "the left to the right", so just multiply by ten and add the digit. Rinse and repeat until you have no digits left and put the result on the stack.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define SIZE 6
/* you should look up what "static" means and when and how to use */
static int stack[SIZE]; //stack size
static int top = 0; //top of stack
/*
* You need to expicitely add "void" to the argumet list.
* It defaults to "int" otherwise.
* Please do yourself a favor and switch all warnings on.
*/
void pop(void);
void clear(void);
void display(void);
void top_element(void);
void add(void);
void multiply(void);
void subtract(void);
void division(void);
void power(void);
/* Most checks and balances omitted! */
int main(void)
{
/* "int" to make things easier */
int input;
int flag = 1, anumber;
while (flag == 1) {
printf(": ");
/* get a(n ASCII) character */
input = fgetc(stdin);
if (isdigit(input)) {
anumber = 0;
/*
* We have a digit. Parse input for more digits until
* no further digits appear and add all digits to "anumber".
* We assume a decimal representation here.
*/
/* TODO: check for overflow! */
for (;;) {
anumber *= 10;
anumber += input - '0';
input = fgetc(stdin);
if (!isdigit(input)) {
break;
}
}
/* Push number on the stack */
if (top < SIZE) {
stack[top] = anumber;
top++;
} else {
printf("Error: stack overflow\n");
}
}
/* "input" from fgetc() is an integer, we can use a switch */
switch (input) {
case 'p':
pop();
break;
case 'c':
clear();
break;
case 'd':
display();
break;
case '=':
top_element();
break;
case '+':
add();
break;
case '^':
power();
break;
case 'q':
flag = 0;
break;
default:
printf("Error: invalid command\n");
break;
}
}
printf("Goodbye!\n");
return 0;
}
void pop(void)
{
if (top == 0)
printf("Error: stack is empty\n");
else
top--;
}
void clear(void)
{
top = 0;
}
void display(void)
{
int i;
if (top == 0)
printf("Error: stack is empty\n");
else {
for (i = top - 1; i >= 0; i--)
printf("%d\n", stack[i]);
}
}
void top_element(void)
{
printf("%d\n", stack[top - 1]);
}
void add(void)
{
if (top < 2)
printf("Error: not enough operands for the requested operation\n");
else {
int ans = stack[top - 1] + stack[top - 2];
stack[top - 2] = ans;
top--;
}
}
/* Using pow() from math.h is not a good idea beause it uses floating point */
/* TODO check for overflows! */
static int integer_pow(int x, int n)
{
int r;
r = 1;
while (n != 0) {
if (n & 1) {
r *= x;
}
x *= x;
n >>= 1;
}
return r;
}
void power(void)
{
if (top < 2)
printf("Error: not enough operands for the requested operation\n");
else {
int ans = integer_pow(stack[top - 2], stack[top - 1]);
stack[top - 2] = ans;
top--;
}
}
Test:
$ ./stackbcalc
: 123+23=
Error: not enough operands for the requested operation
: 23
: Error: invalid command
: q
Goodbye!
Does not work. Why? The function add() expects two operands on the stack. You need to put the + also on the stack (it is an integer) and once you are at the end with = you can evaluate the stack. You might need to learn something about infix/postfix/prefix notation to succesfully do so.
Hint: I would also ignore whitespace (space and tab, maybe even return) in the switch.

I'm facing a runtime error in a c program that should convert from infix to postfix notation

I'm writing a program that should read equations from a txt file and fill them in a linked-list, check their validity and then convert each valid equation to post-fix notation and calculate the final result. Then write them to a file or print them on the console depends on the user choice. Following is what I've already done, I know my code is really long but I posted it all in order to make my question more clear:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node *ptr;
struct node
{
char eq[100];
char pstfix[100];
double result;
ptr next;
int topPST;
int topOP;
int validity;
};
typedef ptr list;
typedef ptr position;
list l;
void menu(); // prints the menu
void readFile(list l); //reads data from a file
int opPriority(char operators[],char operation,int top) ; // check the priority of a given operation
void isValid(position p);//Function to check the validity of each equation.
void convert(list l); // to convert from infix to postfix
void getResult(list l); // to calculate the result of an equation
double calculate(char operation, int op1,int op2);//To return the value in each step when getting the result
void showValidity(list l); // print the equations and show the ones that have errors
void acceptEq(list l); // Let the user enter equations on the console screen
void fillInfix(position p, char c[]);//A function to fill the array of infix in the node.
int isNum(char val);//returns if the value passed to it is a number or character.
void writeToFile(list l);//Write to the file
void showConsole(list l);//Show the final results on the console
int main()
{
printf("\t\t\t*Data Structure\tSecond project*\n\n\t\t\t*Convert from infix to postfix*\n\n");
menu();
l=(list)malloc(sizeof(struct node));
return 0;
}
//Function to print the menu and let the program work depending on the choice.
void menu()
{
system("cls");
int choice;
printf("\t\t\t\tMenu\n\n\t\t\t1.Read equations from file.\n\t\t\t2.Check validity.\n\t\t\t3.Convert to postfix.\n\t\t\t4.Add more equations to the file.\n\t\t\t\n\t\t\t5.Calculate Results.\n\t\t\t6.Write results to file.\n\t\t\t7.Show results on the console.\n\t\t\t8.End.\n\n\t\t\tEnter Your choice number please\n\t\t\t");
scanf("%d",&choice);
switch (choice)
{
case 1: readFile(l);
break;
case 2: isValid(l);
break;
case 3: convert(l);
break;
case 4: acceptEq(l);
break;
case 5: getResult(l);
break;
case 6: writeToFile(l);
break;
case 7: showConsole(l);
break;
case 8: exit(0);
}
}
//The following function should read equations from a file specified by the user
void readFile(list l)
{
system("cls");
char fileName[50];
FILE *eqFile;
printf("\t\t\tEnter the title of the file please\n\t\t\t");
scanf("\t\t\t%s",fileName);
eqFile=fopen(fileName,"r");
//To ensure the existence of the requested file.
while (eqFile == NULL)
{
printf("\t\t\tThe file you asked for does not exist. Enter another name or enter 'back' to return to menu\n\t\t\t");
scanf("\t\t\t%s",fileName);
if(strcmp(fileName,"back")==0) menu();
else eqFile=fopen(fileName,"r");
}
(l)->next=(position)malloc(sizeof (struct node));
position temp=(l)->next;
char line[100];
while (temp != NULL){
while (fgets(line,sizeof line, eqFile) != NULL)
{
isValid(temp);
if ((temp)->validity) fillInfix(temp,line);
temp=(temp)->next;
(temp)->next=NULL;
}
}
fclose(eqFile);
int choice;
printf("\t\t\tData Read Successfully\n\t\t\tEnter 0 to exit or 1 to return to menu\n\t\t\t");
scanf("%d",&choice);
if (choice) menu();
else exit(0);
}
void isValid(list l)
{
system("cls");
position temp;
temp=l;
int i,count=0;
while((temp)->next!=NULL)
{
for (i=0;i<100;i++)
{
if (((l)->eq[i]=='+' && (l)->eq[i+1]=='*') || ((l)->eq[i]=='-' && (l)->eq[i+1]=='*')|| ((l)->eq[i]=='*' && (l)->eq[i+1]=='/') || ((l)->eq[i]=='/' && (l)->eq[i+1]=='+')|| ((l)->eq[i]=='/' && (l)->eq[i+1]=='-') || (l)->eq[i]==' ')
count++;
}
if (count!=0) (temp)->validity=0;
temp=(temp)->next;
}
int choice;
printf("\t\t\tChecking validity is done enter 0 to quite or 1 to return to menu\n\t\t\t");
scanf("%d",&choice);
if(choice) menu();
else exit(0);
}
void fillInfix(position p, char line[])
{
int i;
for (i=0;i<100;i++)
{
while (line[i]!='\0')
{
(p)->eq[i]=line[i];
}
}
}
void push(char st[],char element, int top)
{
++top;
st[top]=element;
}
char pop(char st[],int top)
{
char elemnt=st[top];
--top;
return elemnt;
}
int opPriority(char operators[], char operation, int top)
{
if ((operation=='*' && operators[top]=='-') || (operation=='*' && operators[top]=='+') || (operation=='*' && operators[top]=='/') || (operation=='/' && operators[top]=='-')|| (operation=='/' && operators[top]=='+') || (operation=='+' && operators[top]=='-')) return 0;
else
if ((operation=='(' && operators[top]=='*') || (operation=='(' && operators[top]=='/') || (operation=='(' && operators[top]=='+') || (operation=='(' && operators[top]=='-')) return 0;
else if (operation==')') return 2;
else
return 1;
}
int isNum(char val)
{
if (val!='+' && val!='-' && val!='*' && val!='/') return 1;
else return 0;
}
void convert(list l)
{
position temp=l;
int i;
char operators[100];
while ((temp)->next != NULL)
{
temp=(temp)->next;
if ((temp)->validity)
{
for (i=0;i<100;i++)
{
if (isNum((temp)->eq[i])) push((temp)->pstfix,(temp)->eq[i],(temp)->topPST);
else
{
int priority=opPriority(operators,(temp)->eq[i],(temp)->topOP);
if (priority==1)
{
push((temp)->pstfix,pop(operators,(temp)->topOP),(temp)->topPST);
push(operators,(temp)->eq[i],(temp)->topOP);
}
else
if (priority ==0) push(operators,(temp)->eq[i],(temp)->topOP);
else
if (priority==2)
{
while (operators[(temp)->topOP]!='(')
{
push((temp)->pstfix,pop(operators,(temp)->topOP),(temp)->topPST);
}
char trash=pop(operators,(temp)->topOP);//Unwanted closed bracket
}
}
}
}
}
int choice;
printf("\t\t\tConversion Done successfully. Enter 0 to quite or 1 to return to menu\n\t\t\t");
scanf("%d",&choice);
if(choice) menu();
else exit(0);
}
void acceptEq(list l)
{
system("cls");
char newEq[100];
printf("\t\t\t Enter your equation please. Note that your equation must not exceed the 100 characters length.\n\t\t\t");
scanf("\t\t\t%s",newEq);
position temp=l;
position p=(position)malloc(sizeof (struct node));
while ((temp)->next!=NULL)
{
temp=(temp)->next;
}
(temp)->next=p;
isValid(p);
if ((p)->validity)
{
fillInfix(p,newEq);
convert(p);
}
}
void getResult(list l)
{
system("cls");
position temp=l;
while ((temp)->next != NULL)
{
temp=(temp)->next;
int i=0;
while ((temp)->pstfix[i]!= '\0')
{
if ((temp)->pstfix[i]=='+' || (temp)->pstfix[i]=='-' || (temp)->pstfix[i]=='*' || (temp)->pstfix[i]=='/')
(temp)->result = calculate((temp)->pstfix[i],(temp)->pstfix[i-2],(temp)->pstfix[i-1]);
push((temp)->pstfix,(temp)->result,(temp)->topPST);
printf("\n\t\t\t%c",(temp)->pstfix[i]);
i++;
}
printf("=%f",(temp)->result);
}
}
double calculate (char operation,int op1,int op2)
{
double result;
if (operation=='+') result=op1+op2;
if (operation=='-') result=op1-op2;
if (operation=='*') result=op1*op2;
if (operation=='/') result=op1/op2;
return result;
}
void writeToFile(list l)
{
system("cls");
char fileWName[50];
printf("\n\t\t\tEnter the name of the file you want to print on please\n\t\t\t");
scanf("\t\t\t%s",fileWName);
FILE* resultFile;
resultFile=fopen(fileWName,"w");
position temp=l;
fprintf(resultFile,"Infix Notation:\t\t");
fprintf(resultFile,"Validity:\t\t");
fprintf(resultFile,"Postfix Notation:\t\t");
fprintf(resultFile,"Value:\t\t\n");
while ((temp)->next != NULL)
{
temp=(temp)->next;
int i=0;
while ((temp)->eq[i]!='/0')
{
fprintf(resultFile,"%c",(temp)->eq[i]);
i++;
}
fprintf(resultFile,"\t\t");
i=0;
while ((temp)->pstfix[i]!='/0')
{
fprintf(resultFile,"%c",(temp)->pstfix[i]);
i++;
}
fprintf(resultFile,"\t\t");
if ((temp)->validity == 0) fprintf(resultFile,"INVALID");
else
{
fprintf(resultFile,"VALID\t\t");
fprintf(resultFile,"%f",(temp)->result);
}
}
fclose(resultFile);
int choice;
printf("\t\t\tDATA WRITTEN TO FILE SUCCESSFULLY. Press 1 to return to menu or 0 to quite\n\t\t\t");
scanf("%d",&choice);
if (choice) menu(l);
else exit(0);
}
void showConsole(list l)
{
system("cls");
position temp=l;
printf("Infix Notation:\t\t");
printf("Validity:\t\t");
printf("Postfix Notation:\t\t");
printf("Value:\t\t\n");
while ((temp)->next != NULL)
{
temp=(temp)->next;
int i=0;
while ((temp)->eq[i]!='/0')
{
printf("%c",(temp)->eq[i]);
i++;
}
printf("\t\t");
i=0;
while ((temp)->pstfix[i]!='/0')
{
printf("%c",(temp)->pstfix[i]);
i++;
}
printf("\t\t");
if ((temp)->validity == 0) printf("INVALID");
else
{
printf("VALID\t\t");
printf("%f",(temp)->result);
}
}
int choice;
printf("\t\t\tDATA WRITTEN SUCCESSFULLY. Press 1 to return to menu or 0 to quite\n\t\t\t");
scanf("%d",&choice);
if (choice) menu();
else exit(0);
}
I've already used debugger to find out where my problem is. And now I know that there's a compiling error in this statement:
(l)->next=(position)malloc(sizeof (struct node));
I'm wondering what's wrong with this statement? I'm trying to allocate space for a node in order to be able to create more nodes for each line (equation).
In this case it's easy to see what's wrong: You try to dereference a NULL pointer.
To understand why, you should know that all global variables, like the variable l in your program, are zero-initialized. That basically means that the pointer l is initialized to NULL.
The problem arise because memory for l is not allocated until after you call the menu function. So any function called from menu will have l equal NULL.
There are a few other problems with your code. One is that memory you allocate with malloc is not initialized at all, so for example when you later in the readFile function call isValid with the newly allocated node, and in isValid dereference the temp->next pointer, the value of that next pointer is indeterminate (and in reality will be seemingly random). Accessing uninitialized data like that will lead to undefined behavior. This of course goes for all data inside the structure, not just pointers.
You also don't seem to set temp->validity to non-zero anywhere.

Resources