Original Post
Hey everyone, this fall semester I had a couple of University Programming Projects for the Computer Science class I was in. I was wonder if I could get some advice on the code I wrote for them. The projects are completely finished and have been completely graded. I will start with just the second project we had (The first one was pretty easy and I did post the code to it here a couple months ago).
The second project we had was to create our own bare bones basic stack class and use that to convert basic infix to postix
Example:
[source lang="cpp"]5+5 -> 55+
or
5+5-3 -> 55+3-[/source]
we did not have to have it be able to use parenthesis.
The requirements were to create our own stack class (bare bones basic) and we could not use the std::stack class in STL. The user would just have to type in convert, a basic infix expression and then convert. We had to do some basic error checking (like the user didn't just type in "5/" though we were allowed to assume some things (though I did try to check for only integer input)
I am wondering if some people could take a look at the code and see how it is. What are some things you would improve? Advice? Comments? Suggestions? I will take any input!
Also the grade I made on this was a 99, with one point being taken off because most of the code was in main.cpp and didn't split it into multiple functions. Though a 99 was the lowest grade I made out of all my other programming assignments with me making 100's on the rest (will post later on after input with this one, to get input on those). The Teacher Assistant seemed to like my solutions a little more than others though it seemed, so I was glad to hear that.
NOTE: I wrote the static CommandProcessor class to use on all my projects to try to help me with the command input
EDIT: I did have more of my functions in the Stack class returning NULL if they failed or something like that, though when I had to upload it the command line compiler that the servers used (a linux compiler) did not like me using NULL in those places, so I just replaced those with a return ' ' instead. I don't seem to be the biggest fan of the compiler used on the servers, but oh well. Visual Studio has zero problems with my code with me using NULL.
CommandProcessor.h
[source lang="cpp"]//CommandProcessor Header File
//Class for CommandProcessor
//Static Class to for processing commands and arguments
//only include once in the compiling/linking process
#ifndef COMMANDPROCESSOR_H
#define COMMANDPROCESSOR_H
//string for working with C++ strings
#include
class CommandProcessor
{
public:
//ExtractCommand will extract the command that was entered
static std::string ExtractCommand(std::string& line);
//ExtractArgument will extract the argument that was entered in the command
static std::string ExtractArgument(std::string& line);
//CheckArgument will make sure their is an argument in the command
static bool CheckArgument(std::string& line);
};
#endif[/source]
CommandProcessor.cpp
[source lang="cpp"]//CommandProcessor Class Definition Source File
//Definition for Static Class CommandProcessor
//include the header file for the class
#include "CommandProcessor.h"
//start the class definitions
std::string CommandProcessor::ExtractCommand(std::string& line)
{
//hold the index/location of the space in the command
int index=line.find(" ");
//if the string does not contain a space it will return string::npos
if(index==std::string::npos)
{
//return the entire line
//no arguments found
return line;
}
else
{
//return the command up until the arguments start
return line.substr(0, index);
}
}
std::string CommandProcessor::ExtractArgument(std::string& line)
{
//hold the index/location of the space in a line
int index=line.find(" ");
//if the string does not contain a space, return an empty string
if(index==std::string::npos)
{
return "";
}
else
{
//return a substring
//from one character after the space to the end of the line
//length-index-1 to take account for the characters we don't need and the one space we moved over
return line.substr(index+1, line.length()-index-1);
}
}
//CheckArgument will make sure that an argument is present in the command
//returns true if the argument was present
//returns falsee if the argument was not present
bool CommandProcessor::CheckArgument(std::string& line)
{
//if argument is not an empty string then we consider it a valid argument
//will keep program specific argument checking outside this class for code reusability
if(line=="")
{
return false;
}
//the argument was not a empty string, consder it valid right now and return true
return true;
}[/source]
Node.h
[source lang="cpp"]//Node.h
//Header file for the Node Struct
//Declares the Node Struct
#ifndef NODE_H
#define NODE_H
//Node Struct
//A node simply is a datatype, build as a struct
struct Node
{
//the data in the node will hold both operators and numbers.
int data;
//point to the next node in the stack
Node* nextNode;
};
#endif[/source]
Stack.h
[source lang="cpp"]//Stack.h
//Header file to declare the Stack Class
#ifndef STACK_H
#define STACK_H
//include iostream so we can compare things to NULL
#include
//Stack will use the Node datatype
#include "Node.h"
//start the clas declaration of the List based Stack
class Stack
{
private:
//hold a pointer to the first Node in the stack
Node* firstNode;
//hold the size of the current stack
int size;
public:
//Public methods for working generally with stacks
//Public default constructor
Stack();
//Push will put some data onto the Stack
void Push(char data);
//Pop will remove the first element or Node
char Pop();
//prints out the data of the first node
char Top();
};
#endif[/source]
Stack.cpp
[source lang="cpp"]//Stack class definition source file
//Define what the Stack class is
//include the Stack header file
#include "Stack.h"
Stack::Stack()
{
//the first pointer is null or empty at the start
firstNode=NULL;
size=0;
}
//Push Method
//Takes in a char datatype and pushes the data onto the top of the Stack
void Stack::Push(char data)
{
//create a temporary Node at first
Node* tempNode=new Node();
//store the data needed into the temporary node
tempNode->data=data;
//before we push make sure that the first node isn't null
if(firstNode!=NULL)
{
//the first node isn't null
//the next node in the list now holds the first node
tempNode->nextNode=firstNode;
//the first node in the list now holds the tempNode, or the newNode that needs to be entered
firstNode=tempNode;
}
//if anything else then we now know the firstNode is null
else
{
//since it was empty already we can simply add the new node the list
//be setting the firstNode equal to the new tempNode
firstNode=tempNode;
tempNode->nextNode=NULL;
}
//increase the size
size++;
}
char Stack::Pop()
{
char dataReturn=firstNode->data;
//check to make sure the size of the stack is not empty
//since we increased the size evertime we added a new node, we can just check the size
if(size<=0)
{
//we can't pop anything off the stack if it is empty
return ' ';
}
//create a temporary node to hold the first node
Node* tempNode=firstNode;
//the first node is now the node that was next
firstNode=firstNode->nextNode;
delete tempNode;
size--;
return dataReturn;
}
//returns the char data in the top node on the stack
//will return null if the stack is empty and the top of the stack is null
char Stack::Top()
{
if(firstNode==NULL)
{
return ' ';
}
return firstNode->data;
}[/source]
and finally Main.cpp
[source lang="cpp"]//Program2
//Infix to Postfix
//Main.cpp
//Main Source file for Program2
//iostream for console input and output
#include
//include the static class CommandProcessor
#include "CommandProcessor.h"
//Include Stack for a stack
#include "Stack.h"
//Function Prototypes
//Check to see if the string passed in is valid argument
bool ValidArgument(std::string& input);
//Do the conversion of infix to postfix in this function
void Convert(std::string& input);
//Checks to see if the characters in the arguments are numbers or operators
bool IsNumber(char input);
//Checks to see if the given operator is equal or lower to another operator
bool IsLowerOperator(char readingOperator, char stackOperator);
//main entry point
int main()
{
//the beginning text that gets added on to just about everything
const std::string BEGINNING_TEXT= "infix_to_postfix> ";
//hold the input
std::string input;
//hold the command input string
std::string commandInput="";
//hold the argument input string
std::string argumentInput="";
//boolean variable to know when the program should keep running or not
//running will be true when we need to keep running. false when we should quit
bool running=true;
while(running)
{
std::cout< std::getline(std::cin, input);
commandInput=CommandProcessor::ExtractCommand(input);
argumentInput=CommandProcessor::ExtractArgument(input);
//if we need to convert
if(commandInput=="convert")
{
if(ValidArgument(argumentInput))
{
Convert(argumentInput);
}
else
{
std::cout<<"Error! Not a valid argument!"< }
}
//command was to quit
else if(commandInput=="quit")
{
running=false;
}
//command was not reconized
else
{
std::cout<<"Error! Command not reconized!"< }
}
//return 0 for no error
return 0;
}
bool ValidArgument(std::string& input)
{
//boolean variable to keep track weather or not the input was valid
bool validInput=false;
if(CommandProcessor::CheckArgument(input))
{
//argument was not empty
//loop through the string to make sure it is a valid postfix
//only numbers and operators
for(unsigned int i=0; i {
//if the postfix argument was not a number or a operator set validInput to false;
if(!(input=='0'||input=='1'||input=='2'||input=='3'||input=='4'||input=='5'||input=='6'||input=='7'||input=='8'||input=='9' //check for numbers
||input=='+'||input=='-'||input=='*'||input=='/')) //check for all the operators
{
validInput=false;
//break out of the loop
break;
}
else
{
validInput=true;
}
}
}
//we now know that the argument was empty
else
{
validInput=false;
}
return validInput;
}
//Takes in a input string and converts it from Infix to Postfix
void Convert(std::string& input)
{
std::string output;
//a stack will hold the operators
Stack postFix;
//loop through the input string
for(unsigned int i=0; i {
//check to see if the character is a number or operator
if(IsNumber(input))
{
//it is a number, it goes straight to the output
output+=input;
}
else
{
//first check to see if there was anything on the stack
//if not then push the operator onto the stack
if(postFix.Top()==' ')
{
postFix.Push(input);
}
//if the operator is of lower or equal precedence then pop the operator on top and append it to the output until the top element is no longer higher precedence
else if(IsLowerOperator(input, postFix.Top()))
{
do
{
output+=postFix.Pop();
}
while(IsLowerOperator(input, postFix.Top()));
postFix.Push(input);
}
//the operator is of higher precendence, just push it onto the stack
else
{
postFix.Push(input);
}
}
}
//we are outside the for loop, all the elements are read, pop all the elements
//keep "popping" until the top element is NULL
while(postFix.Top()!=' ')
{
output+=postFix.Pop();
}
std::cout< }
//Returns true if the input character is a number
//returns false if it is a operator
bool IsNumber(char input)
{
//if the input is an operator return false
if(input=='*'||input=='/'||input=='-'||input=='+')
{
//number is an operator return false
return false;
}
//return true because we now know it has to be a number
//this function would not be called if an alpha character was in the string
return true;
}
//Returns true if the first operator is lower or equal precedence to the one on top of the stack
//returns false if it is not
bool IsLowerOperator(char readingOperator, char stackOperator)
{
//is the value of equal or lower precedence
if((readingOperator=='-'&&stackOperator=='+')||(readingOperator=='-'&&stackOperator=='-')||(readingOperator=='+'&&stackOperator=='-')||(readingOperator=='+'&&stackOperator=='+')
||(readingOperator=='-'&&stackOperator=='*')||(readingOperator=='-'&&stackOperator=='/')||(readingOperator=='+'&&stackOperator=='*')||(readingOperator=='+'&&stackOperator=='/')
||(readingOperator=='*'&&stackOperator=='*')||(readingOperator=='*'&&stackOperator=='/')||(readingOperator=='/'&&stackOperator=='/')||(readingOperator=='/'&&stackOperator=='*'))
{
//return true as the operator was of equal or lower precendence
return true;
}
//it is not lower or equal value, return false
else
{
return false;
}
}[/source]
The second project we had was to create our own bare bones basic stack class and use that to convert basic infix to postix
Example:
[source lang="cpp"]5+5 -> 55+
or
5+5-3 -> 55+3-[/source]
we did not have to have it be able to use parenthesis.
The requirements were to create our own stack class (bare bones basic) and we could not use the std::stack class in STL. The user would just have to type in convert, a basic infix expression and then convert. We had to do some basic error checking (like the user didn't just type in "5/" though we were allowed to assume some things (though I did try to check for only integer input)
I am wondering if some people could take a look at the code and see how it is. What are some things you would improve? Advice? Comments? Suggestions? I will take any input!
Also the grade I made on this was a 99, with one point being taken off because most of the code was in main.cpp and didn't split it into multiple functions. Though a 99 was the lowest grade I made out of all my other programming assignments with me making 100's on the rest (will post later on after input with this one, to get input on those). The Teacher Assistant seemed to like my solutions a little more than others though it seemed, so I was glad to hear that.
NOTE: I wrote the static CommandProcessor class to use on all my projects to try to help me with the command input
EDIT: I did have more of my functions in the Stack class returning NULL if they failed or something like that, though when I had to upload it the command line compiler that the servers used (a linux compiler) did not like me using NULL in those places, so I just replaced those with a return ' ' instead. I don't seem to be the biggest fan of the compiler used on the servers, but oh well. Visual Studio has zero problems with my code with me using NULL.
CommandProcessor.h
[source lang="cpp"]//CommandProcessor Header File
//Class for CommandProcessor
//Static Class to for processing commands and arguments
//only include once in the compiling/linking process
#ifndef COMMANDPROCESSOR_H
#define COMMANDPROCESSOR_H
//string for working with C++ strings
#include
class CommandProcessor
{
public:
//ExtractCommand will extract the command that was entered
static std::string ExtractCommand(std::string& line);
//ExtractArgument will extract the argument that was entered in the command
static std::string ExtractArgument(std::string& line);
//CheckArgument will make sure their is an argument in the command
static bool CheckArgument(std::string& line);
};
#endif[/source]
CommandProcessor.cpp
[source lang="cpp"]//CommandProcessor Class Definition Source File
//Definition for Static Class CommandProcessor
//include the header file for the class
#include "CommandProcessor.h"
//start the class definitions
std::string CommandProcessor::ExtractCommand(std::string& line)
{
//hold the index/location of the space in the command
int index=line.find(" ");
//if the string does not contain a space it will return string::npos
if(index==std::string::npos)
{
//return the entire line
//no arguments found
return line;
}
else
{
//return the command up until the arguments start
return line.substr(0, index);
}
}
std::string CommandProcessor::ExtractArgument(std::string& line)
{
//hold the index/location of the space in a line
int index=line.find(" ");
//if the string does not contain a space, return an empty string
if(index==std::string::npos)
{
return "";
}
else
{
//return a substring
//from one character after the space to the end of the line
//length-index-1 to take account for the characters we don't need and the one space we moved over
return line.substr(index+1, line.length()-index-1);
}
}
//CheckArgument will make sure that an argument is present in the command
//returns true if the argument was present
//returns falsee if the argument was not present
bool CommandProcessor::CheckArgument(std::string& line)
{
//if argument is not an empty string then we consider it a valid argument
//will keep program specific argument checking outside this class for code reusability
if(line=="")
{
return false;
}
//the argument was not a empty string, consder it valid right now and return true
return true;
}[/source]
Node.h
[source lang="cpp"]//Node.h
//Header file for the Node Struct
//Declares the Node Struct
#ifndef NODE_H
#define NODE_H
//Node Struct
//A node simply is a datatype, build as a struct
struct Node
{
//the data in the node will hold both operators and numbers.
int data;
//point to the next node in the stack
Node* nextNode;
};
#endif[/source]
Stack.h
[source lang="cpp"]//Stack.h
//Header file to declare the Stack Class
#ifndef STACK_H
#define STACK_H
//include iostream so we can compare things to NULL
#include
//Stack will use the Node datatype
#include "Node.h"
//start the clas declaration of the List based Stack
class Stack
{
private:
//hold a pointer to the first Node in the stack
Node* firstNode;
//hold the size of the current stack
int size;
public:
//Public methods for working generally with stacks
//Public default constructor
Stack();
//Push will put some data onto the Stack
void Push(char data);
//Pop will remove the first element or Node
char Pop();
//prints out the data of the first node
char Top();
};
#endif[/source]
Stack.cpp
[source lang="cpp"]//Stack class definition source file
//Define what the Stack class is
//include the Stack header file
#include "Stack.h"
Stack::Stack()
{
//the first pointer is null or empty at the start
firstNode=NULL;
size=0;
}
//Push Method
//Takes in a char datatype and pushes the data onto the top of the Stack
void Stack::Push(char data)
{
//create a temporary Node at first
Node* tempNode=new Node();
//store the data needed into the temporary node
tempNode->data=data;
//before we push make sure that the first node isn't null
if(firstNode!=NULL)
{
//the first node isn't null
//the next node in the list now holds the first node
tempNode->nextNode=firstNode;
//the first node in the list now holds the tempNode, or the newNode that needs to be entered
firstNode=tempNode;
}
//if anything else then we now know the firstNode is null
else
{
//since it was empty already we can simply add the new node the list
//be setting the firstNode equal to the new tempNode
firstNode=tempNode;
tempNode->nextNode=NULL;
}
//increase the size
size++;
}
char Stack::Pop()
{
char dataReturn=firstNode->data;
//check to make sure the size of the stack is not empty
//since we increased the size evertime we added a new node, we can just check the size
if(size<=0)
{
//we can't pop anything off the stack if it is empty
return ' ';
}
//create a temporary node to hold the first node
Node* tempNode=firstNode;
//the first node is now the node that was next
firstNode=firstNode->nextNode;
delete tempNode;
size--;
return dataReturn;
}
//returns the char data in the top node on the stack
//will return null if the stack is empty and the top of the stack is null
char Stack::Top()
{
if(firstNode==NULL)
{
return ' ';
}
return firstNode->data;
}[/source]
and finally Main.cpp
[source lang="cpp"]//Program2
//Infix to Postfix
//Main.cpp
//Main Source file for Program2
//iostream for console input and output
#include
//include the static class CommandProcessor
#include "CommandProcessor.h"
//Include Stack for a stack
#include "Stack.h"
//Function Prototypes
//Check to see if the string passed in is valid argument
bool ValidArgument(std::string& input);
//Do the conversion of infix to postfix in this function
void Convert(std::string& input);
//Checks to see if the characters in the arguments are numbers or operators
bool IsNumber(char input);
//Checks to see if the given operator is equal or lower to another operator
bool IsLowerOperator(char readingOperator, char stackOperator);
//main entry point
int main()
{
//the beginning text that gets added on to just about everything
const std::string BEGINNING_TEXT= "infix_to_postfix> ";
//hold the input
std::string input;
//hold the command input string
std::string commandInput="";
//hold the argument input string
std::string argumentInput="";
//boolean variable to know when the program should keep running or not
//running will be true when we need to keep running. false when we should quit
bool running=true;
while(running)
{
std::cout<
commandInput=CommandProcessor::ExtractCommand(input);
argumentInput=CommandProcessor::ExtractArgument(input);
//if we need to convert
if(commandInput=="convert")
{
if(ValidArgument(argumentInput))
{
Convert(argumentInput);
}
else
{
std::cout<<"Error! Not a valid argument!"<
}
//command was to quit
else if(commandInput=="quit")
{
running=false;
}
//command was not reconized
else
{
std::cout<<"Error! Command not reconized!"<
}
//return 0 for no error
return 0;
}
bool ValidArgument(std::string& input)
{
//boolean variable to keep track weather or not the input was valid
bool validInput=false;
if(CommandProcessor::CheckArgument(input))
{
//argument was not empty
//loop through the string to make sure it is a valid postfix
//only numbers and operators
for(unsigned int i=0; i
//if the postfix argument was not a number or a operator set validInput to false;
if(!(input=='0'||input=='1'||input=='2'||input=='3'||input=='4'||input=='5'||input=='6'||input=='7'||input=='8'||input=='9' //check for numbers
||input=='+'||input=='-'||input=='*'||input=='/')) //check for all the operators
{
validInput=false;
//break out of the loop
break;
}
else
{
validInput=true;
}
}
}
//we now know that the argument was empty
else
{
validInput=false;
}
return validInput;
}
//Takes in a input string and converts it from Infix to Postfix
void Convert(std::string& input)
{
std::string output;
//a stack will hold the operators
Stack postFix;
//loop through the input string
for(unsigned int i=0; i
//check to see if the character is a number or operator
if(IsNumber(input))
{
//it is a number, it goes straight to the output
output+=input;
}
else
{
//first check to see if there was anything on the stack
//if not then push the operator onto the stack
if(postFix.Top()==' ')
{
postFix.Push(input);
}
//if the operator is of lower or equal precedence then pop the operator on top and append it to the output until the top element is no longer higher precedence
else if(IsLowerOperator(input, postFix.Top()))
{
do
{
output+=postFix.Pop();
}
while(IsLowerOperator(input, postFix.Top()));
postFix.Push(input);
}
//the operator is of higher precendence, just push it onto the stack
else
{
postFix.Push(input);
}
}
}
//we are outside the for loop, all the elements are read, pop all the elements
//keep "popping" until the top element is NULL
while(postFix.Top()!=' ')
{
output+=postFix.Pop();
}
std::cout< }
//Returns true if the input character is a number
//returns false if it is a operator
bool IsNumber(char input)
{
//if the input is an operator return false
if(input=='*'||input=='/'||input=='-'||input=='+')
{
//number is an operator return false
return false;
}
//return true because we now know it has to be a number
//this function would not be called if an alpha character was in the string
return true;
}
//Returns true if the first operator is lower or equal precedence to the one on top of the stack
//returns false if it is not
bool IsLowerOperator(char readingOperator, char stackOperator)
{
//is the value of equal or lower precedence
if((readingOperator=='-'&&stackOperator=='+')||(readingOperator=='-'&&stackOperator=='-')||(readingOperator=='+'&&stackOperator=='-')||(readingOperator=='+'&&stackOperator=='+')
||(readingOperator=='-'&&stackOperator=='*')||(readingOperator=='-'&&stackOperator=='/')||(readingOperator=='+'&&stackOperator=='*')||(readingOperator=='+'&&stackOperator=='/')
||(readingOperator=='*'&&stackOperator=='*')||(readingOperator=='*'&&stackOperator=='/')||(readingOperator=='/'&&stackOperator=='/')||(readingOperator=='/'&&stackOperator=='*'))
{
//return true as the operator was of equal or lower precendence
return true;
}
//it is not lower or equal value, return false
else
{
return false;
}
}[/source]