OK, so I was looking for an algorithm that could help me find a string within a substring.
The code I was using before was from a similar question but it doesn't do it.
// might not be exposed publicly, but could be
int index_of(string const& haystack, int haystack_pos, string const& needle) {
// would normally use string const& for all the string parameters in this
// answer, but I've mostly stuck to the prototype you already have
// shorter local name, keep parameter name the same for interface clarity
int& h = haystack_pos;
// preconditions:
assert(0 <= h && h <= haystack.length());
if (needle.empty()) return h;
if (h == haystack.length()) return -1;
if (haystack.compare(h, needle.length(), needle) == 0) {
return h;
}
return index_of(haystack, h+1, needle);
}
int index_of(string haystack, string needle) {
// sets up initial values or the "context" for the common case
return index_of(haystack, 0, needle);
}
this doesn't return the start index of "el" on the string "hello" and I can't figure it out.
EDIT:
OK, let me show you a bit more of the code including some real-life examples:
I'm trying to analyze a string that is a path to a file I want to sort in my filesystem.
An input example is this:
input:/media/seagate/lol/Sons.of.Anarchy.S04.720p.HDTV.x264/Sons.of.Anarchy.S04E01.720p.HDTV.x264-IMMERSE.mkv
when I try to parse this string to get the name of the by detecting the presence of SxxExx,I look for "s0","S0", etc (I know it's not the best implementation I was just trying to see if it worked and look at the code later). So when I use that input, what I get on the output is:
input:/media/seagate/lol/Sons.of.Anarchy.S04.720p.HDTV.x264/Sons.of.Anarchy.S04E01.720p.HDTV.x264-IMMERSE.mkv
aux: 0p.HDTV.x264-IMMERSE.mkv
input:/media/seagate/lol/Sons.of.Anarchy.S04.720p.HDTV.x264/Sons.of.Anarchy.S04E01.720p.HDTV.x264-IMMERSE.mkv
aux: 1.720p.HDTV.x264-IMMERSE.mkv
input:/media/seagate/lol/Sons.of.Anarchy.S04.720p.HDTV.x264/Sons.of.Anarchy.S04E01.720p.HDTV.x264-IMMERSE.mkv
aux: 264-IMMERSE.mkv
intended output for aux: S04E01.720p.HDTV.x264-IMMERSE.mkv
So as you can see it's just looking for any char that is in the string and stops, which also accounts for the multiple valid "found"s which should've been just the one.
the full code where I'm trying to use this is:
bool StringWorker::isSeries(size_t &i) {
size_t found1, found2, found3, found4, found5, found6;
found1 = input->find_last_of("S0"); //tried several find functions including the
found2 = input->find_last_of("S1"); //index_of() mentioned above in the post
found3 = input->find_last_of("S2");
found4 = input->find_last_of("s0");
found5 = input->find_last_of("s1");
found6 = input->find_last_of("s2");
if (found1 != string::npos) {
if (input->size() - found1 > 6) {
string aux = input->substr(found1, input->size());
cout << "input:" << *input << endl;
cout << "aux: " << aux << endl;
if (isalpha(aux.at(0)) && isdigit(aux.at(1)) && isdigit(aux.at(2))
&& isalpha(aux.at(3)) && isdigit(aux.at(4))
&& isdigit(aux.at(5))) {
i = found1;
return true;
}
}
}
if (found2 != string::npos) {
if (input->size() - found2 > 6) {
string aux = input->substr(found2, input->size());
cout << "input:" << *input << endl;
cout << "aux: " << aux << endl;
if (isalpha(aux.at(0)) && isdigit(aux.at(1)) && isdigit(aux.at(2))
&& isalpha(aux.at(3)) && isdigit(aux.at(4))
&& isdigit(aux.at(5))) {
i = found2;
return true;
}
}
}
if (found3 != string::npos) {
if (input->size() - found3 > 6) {
string aux = input->substr(found3, input->size());
cout << "input:" << *input << endl;
cout << "aux: " << aux << endl;
if (isalpha(aux.at(0)) && isdigit(aux.at(1)) && isdigit(aux.at(2))
&& isalpha(aux.at(3)) && isdigit(aux.at(4))
&& isdigit(aux.at(5))) {
i = found3;
return true;
}
}
}
if (found4 != string::npos) {
if (input->size() - found4 > 6) {
string aux = input->substr(found4, input->size());
cout << "input:" << *input << endl;
cout << "aux: " << aux << endl;
if (isalpha(aux.at(0)) && isdigit(aux.at(1)) && isdigit(aux.at(2))
&& isalpha(aux.at(3)) && isdigit(aux.at(4))
&& isdigit(aux.at(5))) {
i = found4;
return true;
}
}
}
if (found5 != string::npos) {
if (input->size() - found5 > 6) {
string aux = input->substr(found5, input->size());
cout << "input:" << *input << endl;
cout << "aux: " << aux << endl;
if (isalpha(aux.at(0)) && isdigit(aux.at(1)) && isdigit(aux.at(2))
&& isalpha(aux.at(3)) && isdigit(aux.at(4))
&& isdigit(aux.at(5))) {
i = found5;
return true;
}
}
}
if (found6 != string::npos) {
if (input->size() - found6 > 6) {
string aux = input->substr(found6, input->size());
cout << "input:" << *input << endl;
cout << "aux: " << aux << endl;
if (isalpha(aux.at(0)) && isdigit(aux.at(1)) && isdigit(aux.at(2))
&& isalpha(aux.at(3)) && isdigit(aux.at(4))
&& isdigit(aux.at(5))) {
i = found6;
return true;
}
}
}
return false;
}
Can you see anything wrong here?
Why don't you use the find() method of std::string -> link.
This code returns the index through index = sub_str.find("el"):
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string sub_str="abc def ghi jk lmnop hello";
string sub_str2;
size_t index;
index = sub_str.find("el");
sub_str2 = sub_str.substr (index);
cout<<"index = "<<index<<"\n";
cout<<sub_str2<<"\n";
return 0;
}
For finding a substring and its index in a string you can try this out -
int find_sub(const std::string& mstring,sub)
{
int lensub=sub.length(),len=mstring.length(),f=0,pos;
std::string b="";
for(int i=0;i<len-lensub;i++)
{
for(int j=i,k=0;j<i+lensub;j++,k++)
b[k]=mstring[j];
if(b.compare(sub)==0)
{
f=1;
pos=i;
break;
}
}
if(f==1)
cout<<"substring found at: "<<pos+1;
else
cout<<"substring not found!";
return f;
}
You also check how many times substring appears by removing break; and increasing value of f every time. Also get their indexes by converting pos to an array.
Related
So here is my question. I am tring to run a program I found online and it is failing to compile. Why am I getting an error: "array initializer must be an initializer list or string literal" when I am in fact using a string? I know this code works for others running windows, but not for me on the m1 Mac.
I am trying to initialize a string array using
string f[3] = " ";
#include <iostream>
#include <cstdio>
#include <string.h>
#include <unistd.h>
#include <cstdlib>
using namespace std;
int main()
{
bool cont = true;
char buffer[100] = {};
while (cont)
{
cout << "\n\nEnter a command: ";
cin.get (buffer, 90);
//REMOVE
if (strstr (buffer,"remove") != NULL)
{
char* t = strchr (buffer,' ');
if(t != NULL)
{
if(remove( t+1 ) != 0)
cout << "\n\nError deleting the file.";
else
cout << "\n\nThe file has successfully been deleted.";
}
else
cout << "\n\nInvalid command. Filename not entered.";
}
//EXIT
else if (strstr (buffer,"exit") != NULL)
cont = false;
//RENAME
else if (strstr (buffer,"rename") != NULL)
{
char* t = strchr (buffer,' ');
if (t != NULL)
{
char* oldName = t + 1;
char* newName = strchr (oldName, ' ');
if (newName != NULL)
{
char temp[30] = {};
int i = 0;
for(char* start = oldName; start != newName; start++)
{
temp[i] = *start;
i++;
}
newName++;
if(rename( temp , newName ) != 0)
cout << "\nError renaming the file.";
else
cout << "\nThe file has successfully been renamed.";
}
else
cout << "\n\nNew Name of the file not entered.";
}
else
cout << "\n\nInvalid command.";
}
//RMDIR
else if (strstr (buffer,"rmdir") != NULL)
{
char* t = strchr (buffer,' ');
if(t != NULL)
{
if(rmdir( t+1 ) != 0)
cout << "\n\nError deleting the directory.";
else
cout << "\n\nThe directory has successfully been removed.";
}
else
cout << "\n\nInvalid command. DirectoryName not entered.";
}
//ECHO
else if (strstr (buffer,"echo") != NULL)
{
char* t = strchr (buffer,'"');
if (t != NULL)
{
char* data = t + 1;
//Extracting the data
char temp[200] = {};
int i = 0;
for(; data[i] != '"'; i++)
{
temp[i] = data[i];
}
//Checking if filename is given or not
char* fileN = strchr (data + i, ' ') ;
if (fileN != NULL)
{
fileN++;
// create a FILE typed pointer
FILE *file_pointer;
// open the file for writing
file_pointer = fopen (fileN, "w");
if (file_pointer != NULL)
{
// Write to the file
fprintf (file_pointer,"%s", temp);
// Close the file
fclose (file_pointer);
cout << "\n\nThe file has been successfully created.";
}
else
cout << "\n\nCould not create the file.";
}
//If filename isn't given then simply print the data on console
else
{
cout << endl << endl << temp;
}
}
else
cout << "\n\nInvalid command. Data not given";
}
//UNZIP
else if (strstr (buffer,"unzip") != NULL)
{
char* t = strchr (buffer,' ');
if(t != NULL)
{
char temp[50] = "tar xvf";
if( system( strcat(temp,t) ) != 0 )
cout << "\n\nError unzipping the file.";
else
cout << "\n\nThe file has been successfully unzipped.";
}
else
cout << "\n\nInvalid command. FileName not entered.";
}
//ZIP
else if (strstr (buffer,"zip") != NULL)
{
char* t = strchr (buffer,' ');
if(t != NULL)
{
char temp[50] = "tar cvf";
if( system( strcat( temp,t) ) != 0 )
cout << "\n\nError zipping the file.";
else
cout << "\n\nThe file has been successfully zipped.";
}
else
cout << "\n\nInvalid command.";
}
else if (strstr (buffer,"out") != NULL)
{
int i = 1;
//Checking '-l'
bool lineByLine = false;
char* lpos = strstr (buffer,"-l");
if (lpos != NULL)
{
lineByLine = true;
i++;
}
string s(buffer);
string fileN = "";
string delimiter = " ";
size_t pos = 0;
while ( i > 0 )
{
pos = s.find(delimiter);
s.erase(0, pos + delimiter.length());
i--;
}
//Now extracting the file names
string f[3] = " ";
i = 0;
while ( (pos = s.find(delimiter)) != -1)
{
f[i] = s.substr(0, pos);
s.erase(0, pos + delimiter.length());
i++;
}
//if atleast one filename is present
if ( s != "out" && s != "-l" && s != "" )
{
f[i] = s;
//Opening the files and printing the contents
int c;
FILE *file;
int j = 0;
bool delay = false;
char x;
while ( j <= i)
{
char fName[50];
strcpy(fName, f[j].c_str());
//Printing the contents of the file(s)
file = fopen(fName, "r");
char line[256];
cout << "\n\nThe contents of the file " << fName << " are as follows : \n\n";
if (file)
{
if (lineByLine)
{
while (fgets(line, sizeof(line), file))
{
printf("%s", line);
//Delay loop
delay = true;
while(delay)
{
cout << "\n\nPress some key to print the next line\n\n";
getchar();
delay = false;
}
}
}
else
{
while ((c = getc(file)) != EOF)
putchar(c);
}
fclose(file);
}
else
cout << "\n\nCould not open the file " << fName << " .";
j++;
//Delay loop
delay = true;
while(delay)
{
cout << "\n\nPress some key to continue\n\n";
getchar();
delay = false;
}
}
}
else
cout << "\n\nNo filename entered.\n\n";
}
else
cout << "\n\nInvalid Command. Kindly enter a valid command.";
cin.ignore();
}
cout << "\n\n\nExiting the CLI.\n\n";
return 0;
}
If you are trying to create a string of length 3, you should do this:
string f(3, ' ');
If you are trying to create an array of 3 different strings, then the issue with your code is that you have a type mismatch - you are trying to assign a single string to an array of strings. Instead, you would want to do this:
string f[3] = {" ", " ", " "};
Looking at your code, it looks like you want to create an array of strings. However, it also looks like you could be reading in any number of strings (unless there is some logic in your code where you are confident it will always be 3?) so I recommend using a std::vector.
std::vector<std::string> f;
Which you can add strings to with the push_back() method like this:
f.push_back(s.substr(0, pos));
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 months ago.
Improve this question
First and foremost, I ask that anyone who is replying consider these factors. Currently I have very-low knowledge in arrays and enumerations, most of the basics are understood such as what you will see below. I have been trying to figure this problem out for 3 days and now I'm asking for help before I keep burning myself out every 45mins-1hr.
Problem: Write a two-player tic-tac-toe game, allowing two humans to play against each other; use
enums when possible to represent the values of the board
#include<iostream>
#include<string>
bool tie = false;
std::string p1, p2;
enum turnbased{token1, token2, empty};
char space[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int row;
int column;
int token;
void board() //producing the required space[][] coordinates to empty squares
{
std::cout << " | | \n";
std::cout <<" "<<space[0][0]<<" | "<<space[0][1]<<" | "<<space[0][2]<<" \n";
std::cout << " ____|____|____\n";
std::cout <<" "<<space[1][0]<<" | "<<space[1][1]<<" | "<<space[1][2]<<" \n";
std::cout << " ____|____|____\n";
std::cout << " | | \n";
std::cout <<" "<<space[2][0]<<" | "<<space[2][1]<<" | "<<space[2][2]<<" \n";
std::cout << " | | \n";
}
void playerswitch()
{
turnbased assignto = token1; //initializing enum type to define token1 for turns to occur
int token = empty; //declaring token to equivalate to enum variable{empty} in position()
if(assignto)
{
std::cout << p1 << " choose slot for - " << token1;
assignto = token2;
}
else(assignto == token2);
{
std::cout << p2 << " choose slot for - " << token2;
assignto;
}
std::cin >> token;
}
void position()
{
if(empty == 1) // positioning array space
{
row = 0;
column = 0;
}
else if(empty == 2)
{
row = 0;
column = 1;
}
else if(empty == 3)
{
row = 0;
column = 2;
}
else if(empty == 4)
{
row = 1;
column = 0;
}
else if(empty == 5)
{
row = 1;
column = 1;
}
else if(empty == 6)
{
row = 1;
column = 2;
}
else if(empty == 7)
{
row = 2;
column = 0;
}
else if(empty == 7)
{
row = 2;
column = 1;
}
else if(empty == 8)
{
row = 2;
column = 2;
}
else(empty < 1 || empty > 9);
{
std::cout << "Invalid!!!" << std::endl;
}
//token check and execution
if(token1 && space[row][column] != token1 && space[row][column] != token2)
{
space[row][column] = token1;
token2;
}
else if(token2 && space[row][column] != token1 && space[row][column] != token2)
{
space[row][column] = token2;
token1;
}
else{
std::cout << "Invalid space!" << std::endl;
position();
}
playerswitch();
board();
}
//win check
bool results()
{
for(int i = 0; i < 3; i++)
{ //checks horizontally and vertically
if(space[i][0] == space[i][1] && space[i][0] == space[i][2] || space[0][i] == space[1][i] && space[0][i] == space[2][i])
return true;
//checks diagonally
if(space[0][0] == space[1][1] && space[1][1] == space[2][2] || space[0][2] == space[1][1] && space[1][1] == space[2][0])
return true;
for(int j = 0; j < 3; j++)
{
if(space[i][j] != token1 && space[i][j] != token2)
{
return false;
}
}
}
tie = true;
return false;
}
int main()
{
std::cout << "Enter the name of the first player: \n";
getline(std::cin, p1);
std::cout << p1 << " is player1 so he/she will play first \n";
std::cout << "Enter the name of the second player: \n";
getline(std::cin, p2);
std::cout << p2 << " is player2 so he/she will play second \n";
while(!results())
{
board();
playerswitch();
position();
results();
}
if(token1 && tie)
{
std::cout << p2 << " wins!" << std::endl;
}
else if(token2 && tie)
{
std::cout << p1 << " wins!" << std::endl;
}
else
{
std::cout << "It's a draw!" << std::endl;
}
}```
I wont fix your code, but I will help you structure it so you can figure it and future problems out yourself.
First, get rid of all global variables. This is important because the way to reason about code is to look at individual parts in isolation. This is the only, the ONLY, way writing code scales.
To do this, define an interface and a clear job for each of your functions. Maybe add structs to keep data together that belongs together.
After you have changed the functions to work only on their input arguments (look up how functions receive arguments and return values), you can test each function on its own. Make sure your function to read in input works. Make sure your function to manipulate the playing field works. Do all this before you plug them together. This is called unit testing.
Once you are convinced, that regardless the data that your function receives it always does a proper job, plug them together and see if the result works. If it doesn't, your first goal is to figure out which function is broken. Go back to unit testing with new test inputs.
Rinse and repeat until your program works correctly.
I am a beginner at coding and learning C++. I just wrote a code that asks the user to log in, Register, or exit.
I thought doing it through functions would be easier. While checking for the constraints of the username and password for registration(referred to as "Rusr" and "Rpwd" here) the code I've written to check if lowercase, uppercase, and digits are not working. I tried to do it with character array as well but that didn't work. Would really appreciate some help with this.
Here's my code below for further reference:
#include <fstream>
#include <iostream>
#include <string.h>
using namespace std;
bool isvalidName(string Rusr)
{
if(Rusr.length() > 5 && Rusr.length() < 20) // length constraint
return true;
else
cout << "Invalid username" << endl;
{
for(int i = 0; i < Rusr.length(); i++) // check if digits are present
{
if(isdigit(Rusr[i]) == true)
return true;
if(true)
break;
else
cout << "Invalid username";
}
}
{
for(int i = 0; i < Rusr.length(); i++) // check for lowercase
{
if(islower(Rusr[i])) {
return true;
}
if(true)
break;
else
cout << "Invalid username";
}
}
{
for(int i = 0; i < Rusr.length(); i++) // check for uppercase
{
if(isupper(Rusr[i])) return true;
if(true)
break;
else
cout << "Invalid username";
}
}
}
int isvalidPwd(string Rpwd) {
{
if(Rpwd.length() > 8 && Rpwd.length() < 20)
return true;
else
cout << "Invalid password " << endl;
}
{
for(int i = 0; i < Rpwd.length(); i++) {
if(isdigit(Rpwd[i]) == true) return true;
if(true)
break;
else
cout << "Invalid password";
}
}
{
if(!((Rpwd.find("#") == string::npos) ||
(Rpwd.find("#") == string::npos) ||
(Rpwd.find("!") == string::npos) ||
(Rpwd.find("$") == string::npos) ||
(Rpwd.find("%") == string::npos) ||
(Rpwd.find("^") == string::npos) ||
(Rpwd.find("&") == string::npos) ||
(Rpwd.find("*") == string::npos) ||
(Rpwd.find("(") == string::npos) ||
(Rpwd.find(")") == string::npos) ||
(Rpwd.find("_") == string::npos) ||
(Rpwd.find("+") == string::npos) ||
(Rpwd.find("|") == string::npos) ||
(Rpwd.find(">") == string::npos) ||
(Rpwd.find("<") == string::npos) ||
(Rpwd.find("?") == string::npos) ||
(Rpwd.find("/") == string::npos) ||
(Rpwd.find("~") == string::npos) ||
(Rpwd.find(".") == string::npos) ||
(Rpwd.find(",") == string::npos)))
return true;
else
cout << "should contain special characters" << endl;
}
for(int i = 0; i < Rpwd.length(); i++) {
if(islower(Rpwd[i])) return true;
if(true)
break;
else
cout << "should contain lower case";
}
{
for(int i = 0; i < Rpwd.length(); i++) {
if(isupper(Rpwd[i])) return true;
if(true)
break;
else
cout << "Should contain upper case";
}
}
}
int main() {
string Lusr, Lpwd, Rusr, Rpwd, name, pwd;
while(1) {
cout << "___________________________________" << endl;
cout << "Chose 1 to Register or 2 to Login" << endl;
cout << "___________________________________" << endl;
cout << "1.Register" << endl;
cout << "2.Login" << endl;
cout << "3.Exit" << endl;
cout << "___________________________________" << endl;
int choice;
cin >> choice;
if(choice == 1) // register
{
ofstream of("register.txt");
if(!of.is_open()) {
cout << "file not exist" << endl;
}
do {
cout << "Username should contain capital,small letters and "
"numbers. "
<< endl;
cout << "______________________________________" << endl;
cout << "Enter new username:" << endl;
cin.ignore();
getline(cin, Rusr);
isvalidName(Rusr);
} while(isvalidName(Rusr) == true);
do {
cout << "Password should contain capital,small letters,special "
"characters and numbers. "
<< endl;
cout << "_______________________________________" << endl;
cout << "Enter new passsword:" << endl;
getline(cin, Rpwd);
isvalidPwd(Rpwd);
} while(isvalidPwd(Rpwd) == true);
of << Rusr;
of << '\n';
of << Rpwd;
of.close();
}
else if(choice == 2) {
ifstream f("register.txt");
if(!f.is_open()) {
cout << "file not open" << endl;
}
getline(f, name, '\n');
getline(f, pwd, '\n');
f.close();
cout << "Enter username:" << endl;
cin.ignore();
getline(cin, Lusr);
cout << "Enter passsword:" << endl;
getline(cin, Lpwd);
if(Lpwd == pwd && Lusr == name) {
cout << "Welcome " << Lusr << endl;
;
break;
}
cout << "Wrong name and password" << endl;
}
else if(choice == 3) {
return 1;
} else {
cout << "Invalid input!Try again." << endl;
}
}
return 0;
}
With your code, some of your logic is wrong. When you say this
if(Rusr.length() > 5 && Rusr.length() < 20) // length constraint
return true;
else
cout << "Invalid username`enter code here`" << endl;
Any string that is between 5 and 20 characters will be accepted as a valid username. To fix this, you need to go through all your requirements, then return true. If any of the requirements fail, return false. This makes it so that the only way that the username will be valid is if it has already passed all the requirements.
bool isvalidName(string Rusr)
{
if(Rusr.length() < 5 || Rusr.length() > 20) // length constraint
{
std::cout << "invalid username length" << std::endl;
return false;
}
for(int i = 0; i < Rusr.length(); i++) // check if digits are present
{
if(isdigit(Rusr[i])) // if a digit is present, continue
{
break;
}
if(i == Rusr.length() - 1) // No digits were found
{
return false;
}
}
for(int i = 0; i < Rusr.length(); i++) // check for lowercase
{
if(islower(Rusr[i])) {
break;
}
if(i == Rusr.length() - 1) // No lowercase letters were found
{
cout << "Invalid username";
return false;
}
}
for(int i = 0; i < Rusr.length(); i++) // check for uppercase
{
if(isupper(Rusr[i]))
{
break;
}
if(i == Rusr.length() - 1) // No uppercase letters were found
{
cout << "Invalid username";
return false;
}
}
return true;
}
This way, the only way you return true is if it gets past all the constraints.
For the password, you would want to follow this model and adjust for those constraints.
Some other things to watch out for are the extra braces you have included. Best practice is to not change the scope further in than you need to, so you should avoid the braces in almost every case.
Both your functions fail to return the value you've declared that they should return in all branches, so your program has undefined behavior.
Also, the logic is flawed. Example:
bool isvalidName(string Rusr) {
if(Rusr.length() > 5 && Rusr.length() < 20) // length constraint
return true;
else
cout << "Invalid username`enter code here`" << endl;
// .. the rest ...
}
Here you check that the length is [6, 19] characters long - and return true; - that's all it takes to get Rusr approved. None of the other tests in your function will be executed if the name has an approved length.
Your code is riddled with similar mistakes.
for(int i = 0; i < Rusr.length(); i++) // check if digits are present
{
if(isdigit(Rusr[i]) == true) return true;
The first digit you encounter makes isvalidName return true - so now you have a name with an invalid length that contains a digit - approved!
Similar issue below. A name with an illegal length, without digits, that contains a lowercase letter is immediately approved:
for(int i = 0; i < Rusr.length(); i++) // check for lowercase
{
if(islower(Rusr[i])) {
return true;
And finally, if a name with an illegal length, without digits and without lowercase letters contains an uppercase letter, it's approved:
for(int i = 0; i < Rusr.length(); i++) // check for uppercase
{
if(isupper(Rusr[i])) return true;
If none of the above applies - you don't return anything (causing undefined behavior).
Your second function follows this pattern.
I'm aware that there's already stuff here regarding this but I'm just posting to check if my logic lines up with my code (if I'm thinking about this whole infix Postfix thing the way I should be).
The code I've seen regarding this topic on this site look a little different from mine. I'm kind of a novice at C++. Anyway, my code so far looks like it is just fine and should work just fine but it's not working the way it should. I've included my thought process as comments in the code below. Please let me know if what I'm thinking is okay.
Here's the code:
#include <iostream>
#include <stack>
#include <sstream>
#include <string>
using namespace std;
int priority (string item)
{
int prior = 0;
if (item == "(")
{
prior = 1;
}
if ((item == "+") || (item == "-"))
{
prior = 2;
}
else if ((item == "*") || (item == "/"))
{
prior = 3;
}
else
{
prior = 4;
}
return prior;
}
int main()
{
stack<string> st;
string output;
cout << "Welcome. This program will calculate any arithmetic expression you enter" << endl;
cout << "Please enter an arithmetic expression below: " << endl;
char line[256];
cin.getline(line, 256);
string exp;
exp = line;
cout << "This is the expression you entered: ";
cout << exp << endl;
string item;
istringstream iss(exp);
iss >> item;
// While there are still items in the expression...
while ( iss )
{
// If the item is a number
if (isdigit('item') == true)
{
output = output + " " + item;
}
// If the stack is empty
else if (st.size() == 0)
{
st.push(item);
}
// If the item is not a number
else if (isdigit('item') == false)
{
// convert that item in the expression to a string
atoi(item.c_str());
int prior1 = 0;
int prior2 = 0;
// If that string is a LEFT PARENTHESIS
if (item == "(")
{
st.push(item);
}
// If that string is a RIGHT PARENTHESIS
else if (item == ")")
{
while ((st.empty() == false) && (st.top() != "("))
{
output = st.top() + " ";
st.pop();
}
st.pop();
}
else
{
// store what is returned from "priority" in "prior1"
prior1 = priority(item);
// pass item on top of the stack through "priority"
// store that in "prior2;
prior2 = priority(st.top());
// while loop here, while item has a higher priority...
// store numbers in a variable
while (prior1 > prior2)
{
output = output + " " + st.top();
st.pop();
prior2 = priority(st.top());
}
}
}
}
while (st.empty() == false)
{
output = st.top() + " ";
st.pop();
}
cout << "Here's the postfix: " << output << endl;
}
This is for evaluating postfix to an actual answer:
// EVALUATE POSTFIX
stack<int> st2;
string output2;
istringstream iss2(exp);
iss2 >> item;
while (iss)
{
// If the item is a number
if (isdigit('item') == true)
{
st.push(item);
}
if (isdigit('item') == false)
{
// store item in a variable
// pop another item off the stack
// store that in a variable.
// apply operator to both.
// push answer to the top of the stack.
int m = 0;
int n = 0;
int total = 0;
m = st2.top();
st2.pop();
n = st2.top();
st2.pop();
if (item == "+")
{
total = m + n;
st2.push(total);
}
else if (item == "-")
{
total = m - n;
st2.push(total);
// add the thing you popped of the stack with the first thing on the stack
}
else if (item == "*")
{
total = m * n;
st2.push(total);
}
else if (item == "/")
{
total = m / n;
st2.push(total);
}
}
}
cout << "Here's your answer: " << st2.top() << endl;
}
Am I thinking about this whole infix-postfix thing the way I should be? Am I on track to solving this problem? My apologies if this question seems simple. I'm kind of a novice at this. Thank you very much.
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include "NodeType.h"
using namespace std;
// Test if token is an operator
bool isOperator(char token);
int getPrecedence(char token);
bool comparePrecedence(char tokenA, char tokenB);
int main()
{
stack<char> tokenStack;
queue<char> tokenQueue;
string expression= "", postfix= "";
char x;
cout<<"Please enter a mathematical expression: "<<endl;
getline(cin, expression);
cout<<expression.length()<<endl;
for(int i = 0; i <= expression.length(); i++)
{
x = expression[i];
if(isdigit(x))
{
tokenQueue.push(x);
}
if(isOperator(x))
{
while((!tokenStack.empty()) && (comparePrecedence(x, tokenStack.top() == true)))
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
tokenStack.push(x);
}
if(x == '(')
{
tokenStack.push(x);
}
if(x == ')')
{
while((!tokenStack.empty()) && (tokenStack.top() != '('))
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
tokenStack.pop();
}
while(!tokenStack.empty())
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
}
return 0;
}
int getPrecedence(char token)
{
if((token == '+') || (token == '-'))
{
return 1;
}
else if((token == '*') || (token == '/'))
{
return 2;
}
else if ((token == '(') || (token == ')'))
return 0;
else
return 99;
}
// Test if token is an operator
bool isOperator(char token)
{
return token == '+' || token == '-' ||
token == '*' || token == '/';
}
bool comparePrecedence(char tokenA, char tokenB)
{
if(getPrecedence(tokenA) < getPrecedence(tokenB))
return true;
else
return false;
}
For some reason I cannot get my code to work correctly. It always throws a
Thread 1: EXC_BAD_ACCESS (code=EXC_1386_GPFLT) error. It is also not correctly placing the '+' sign when I test using a simple string such as: (3+4).
The Queue should look like: 34+ but it hold 3+4. It seems to me that the '+' operator never gets pushed onto the stack. Can anyone please help me find what I should be focussing my attention on?
Debugging code is a valuable skill to learn, it's my opinion that it should form a much more important part of curricula in schools.
For example, if you modify your code to output all the stack and queue operations thus:
int main()
{
stack<char> tokenStack;
queue<char> tokenQueue;
string expression= "", postfix= "";
char x;
cout<<"Please enter a mathematical expression: "<<endl;
getline(cin, expression);
cout<<expression.length()<<endl;
for(int i = 0; i <= expression.length(); i++)
{
x = expression[i];
if(isdigit(x))
{
tokenQueue.push(x);
cout << "qpush A " << x << '\n';
}
if(isOperator(x))
{
while((!tokenStack.empty()) && (comparePrecedence(x, tokenStack.top() == true)))
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop G " << z << '\n';
cout << "qpush B " << z << '\n';
tokenStack.pop();
}
tokenStack.push(x);
cout << "spush E " << x << '\n';
}
if(x == '(')
{
tokenStack.push(x);
cout << "spush F " << x << '\n';
}
if(x == ')')
{
while((!tokenStack.empty()) && (tokenStack.top() != '('))
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop H " << z << '\n';
cout << "qpush C " << z << '\n';
tokenStack.pop();
}
cout << "spop I " << tokenStack.top() << '\n';
tokenStack.pop();
}
while(!tokenStack.empty())
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop J " << z << '\n';
cout << "qpush D " << z << '\n';
tokenStack.pop();
}
}
return 0;
}
and run it with a simple 3+4, you'll see the following output:
qpush A 3
spush E +
spop J +
qpush D +
qpush A 4
So you are placing the operation on the stack. However, you later take it off the stack and put it on the queue before you place the next digit on the queue.
That's definitely the wrong order but, if you examine the code, it's not just a small snippet that has two lines in the wrong order (that would be too easy).
The code that's doing that transfer from stack to queue is the final while loop in main() which, after every single character, transfers all the items from the stack to the queue, effectively rendering your stack superfluous.
That's where you should be looking but I'll give you a clue. You don't want to be transferring stack to queue after every character, only for those that involve numbers.
There may well be other problems after you solve that one but that method (debugging output every time you do something important) should be able to give you enough information to fix whatever comes along.