Reputation: 65
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).
Upvotes: 0
Views: 70
Reputation: 409166
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.
Upvotes: 1