Reading stack pop/push operations by text-file input - c++

I have a text file with the following contents:
2
S 8
push 2 push 3 push 5 push 7 pop print push 6 print
S 4
pop print push 1 print
An assignment gives:
The first line of the input file means the number of test cases. For each test case, the first character means which container adapter (Stack or Queue) that you need to use Linked lists to implement. The correct output should be:
The values in the stack : 2 3 5
The values in the stack : 2 3 5 6
The values in the stack :
The values in the stack : 1
I've written some working functions for stack and queue struct, though I am working on the input of the stack function first.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void push(int);
int pop();
void printStack();
struct Stack {
int s[100];
int top;
Stack() { top = -1; }
};
Stack st;
void push(int n) {
if (st.top == 99) {
cout << "Stack full" << endl;
}
else {
st.s[++st.top] = n;
}
}
int pop() {
if (st.top == -1) {
cout << "Stack is empty" << endl;
}
else {
return st.s[st.top--];
}
}
void printStack() {
cout << "Elements";
for (int i = 0;i <= st.top;i++) {
cout << st.s[i] << ' ';
}
cout << endl;
}
void clearStack() {
st.top = -1;
}
The main part of the code is giving me trouble. I want to read every token of the text file while keeping the line structure; e.g. being able to parse by order of line. However, I do not know the length of each line, only the number of lines. How may I read the file correctly and finish this assignment?
int main() {
std::ifstream file("input1.txt");
std::string item_name;
int numTestCases;
vector<string> file_content{};
while (std::getline(file, item_name))
{
//cout << item_name << "\n";
char str[252];
strcpy(str, item_name.c_str());
char* pch;
//cout << "str0:" << str[0] << "\n";
file_content.push_back(str);
}
cout << "printing file content:" << endl;
for (int i = 0;i < file_content.size(); i++) {
cout << file_content[i] << endl;
}
}

Okay, you basically have two distinct problems.
Read your input file so you know what actions to perform.
Implement both Stack and Queue.
So start by breaking them up. I looked at your stack code. Your problem says to use linked lists, which isn't what you're doing. Maybe that's just because you haven't gotten that far yet.
Code like this would give you the number of test cases.
std::string numCasesStr;
if (!getline(file, numCasesStr)) {
cout << "early end of file detected\n";
return;
}
int numCases = std::stoi(numCasesStr);
At this point, you can now do this:
for (int testCase = 0; testCase < numCases; ++testCase) {
std::string typeAndCountStr;
if (!getline(file, typeAndCountStr)) {
cout << "early end of file detected\n";
return;
}
char typeC = typeAndCountStr.at(0);
if (typeC == 'S') {
...
}
else if (typeC == 'Q') {
...
}
}
The harder part is parsing the next line. You're going to get input in a similar fashion, but then you have to break it into pieces. This is called tokenizing. Basically you split it at each space. What's useful is the find method on a string.
do {
size_t lastPos = 0;
size_t pos = str.find(' ', lastPos);
string thisArg;
if (pos != string::npos) {
thisArg = str.substr(lastPos, pos);
lastPos = pos + 1;
}
else {
thisArg = str.substr(lastPos);
}
// At this point, thisArg contains one argument. You still have more
// to do, but this is one way to split your string into pieces.
} while (lastPos != string::npos);
What I do with that is stuff the individual pieces into a std::vector<std::string> and now it's a lot easier to deal with. You can traverse the vector, looking at each string, and depending upon what it is, you know if you have to grab the next item in the list (like push 8 -- you get push and then you get the 8) or just use the current item.
Overall -- break the problem down into smaller pieces. For main:
Get the number of test cases
Loop from 0..testCaseCnt
Get the type of tests (stack or queue)
Get the next input
Split it into tokens broken at each space
Traverse the tokens and Do The Right Thing (tm).

Code for main to read inputs:
int main() {
int numTestCases;
vector<string> file_content{};
fstream ifs;
ifs.open("input2.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
}
else {
ifs >> numTestCases;
char type;
int numberOps;
//ifs >> type;
cout << numTestCases;
for (int j = 0;j < numTestCases;j++) {
ifs >> type;
ifs >> numberOps;
if (type == 'S') {
Stack st;
clearStack();
for (int i = 0;i < numberOps;i++) {
string operation;
ifs >> operation;
if (operation == "push") {
int pushed;
ifs >> pushed;
push(pushed);
}
if (operation == "pop") {
pop();
}
if (operation == "print") {
printStack();
}
}
}
}
ifs.close();
}
}

Related

how to store user input into array in C++

I am new to C++, and want to ask this basic question
what i want: user input data like 2:3American, 4:2China (this means my country team wins 2 points lose 3 points againts American. my country team win 4 points and China team win 2 points)
in console:
please input the result for your team against other teams, input negative number to exit
2:3American
4:2China
-1
result win:1
lose:1
draw:0
If there is no specific encoding is given to you by some authority, use as simple as possible. A better was "2 3 American 4 2 China". So that you only deal with a simple for loop.
The result line is not calculated. Convert each string to integer to calculate.
int main( int argc, char* argv[]) {
std::vector<std::string> arguments(argv + 1, argv + argc);
std::cout << "arguments contains \n";
for (std::vector<std::string>::iterator it = arguments.begin() ; it != arguments.end(); ++it) {
int firstPos = it->find_first_of(":");
int secPos = 0;
std::string firstInteger = it->substr(0,firstPos);
std::string secondInteger;
if ( firstInteger.compare("-1") == 0 ) {
std::cout << "breaking \n";
return 0;
} else {
std::cout << " f=<" << firstInteger << ">";
secPos = it->find_first_not_of( "012345678:", firstPos);
if ( secPos == std::string::npos )
std::cout << "not found";
std::cout << " s=<" << it->substr(firstPos+1 ,secPos-firstPos-1 ) << "> ";
std::string teamName = it->substr(secPos);
std::cout << teamName ;
std::cout << std::endl;
}
}
std::cout << '\n';
return 0;
}
I've written a code similar to this problem a long time ago. made a small change to solve your problem.
So i think this is what you want
INPUT "2:3American 4:2China -1" (SINGLE LINE)
OUTPUT as expected
#include <iostream>
using namespace std;
size_t non_int(int index,string* s)
{
int i=index;
for( i=index;i<s->length();i++){
if(s->at(i) >= '0' && s->at(i) <= '9')
{
// cout << s->at(i) << " is a Digit";
}
else{
return (i-1)<index?(std::string::npos):(i-1);
}
}
return (i-1)<index?(std::string::npos):(i-1);;
}
int main()
{
cout << "Please input the match result such as 2:3American " << endl;
string str;
std::getline (std::cin,str);
//cout<<str;// i want to see did the first user input stored in array. But seems the console..does not print out temp[0] and just skipt it
int win,lose,draw=0;
std::size_t found = 0;
string s1,s2;
int i1,i2;
std::size_t f1,f2;
while( found !=std::string::npos)
{
f1 = str.find(":",found);
if (f1!=std::string::npos){
i1 = stoi(str.substr(found,f1-found));
f2 = non_int(f1+1,&str);
if (f2!=std::string::npos){
i2 = stoi(str.substr(f1+1,f2-f1));
if(i1>i2) win++;
else if(i1<i2)lose++;
else draw++;
}
else {
cout<<"ERROR :invalid input ";
}
}
else {
//exit on -ve input
// cout<<"ERROR 45 ";
}
found = str.find(" ",found+1);
}
cout<<"win:"<<win<<"lose:"<<lose<<"draw:"<<draw<<endl;
return 0;
}
Step 1:
Define a class that represents an input token.
struct Segment
{
int myCountryScore;
int otherCountryScore;
std::string otherCountry;
};
Step 2
Define an input function that reads a Segment from a stream.
std::istream& operator>>(std::istream& s, Segment& data)
{
Segment tmp;
char sep;
int firstNumber;
bool good = false;
if (s >> firstNumber && firstNumber >= 0)
{
tmp.myCountryScore = firstNumber;
if (s >> std::noskipws >> sep >> tmp.otherCountryScore >> tmp.otherCountry >> std::skipws) && (sep == ':'))
{
// The read worked. Copy it to the output object.
data = tmp;
good = true;
}
}
if (!good) {
// If there was an error reading.
// Or we reached the end (negative number read)
// Then set the state of the stream to failure mode.
s.setstate(std::ios::failbit);
}
return s;
}
Step 3
Write a loop that reads Segments from a stream in a loop.
Segment object;
while(std::cin >> object) {
// You have correctly read an object
// Add your code to handle it here.
}
Step 3 Alternative.
Rather than read the Segment one by one you can copy them into a vector simply using a stream iterator.
std::vector<Segment> data(std::istream_iterator<Segment>(std::cin),
std::istream_iterator<Segment>());

How to debug my word search code in C++?

I need some help with my C++ word search code. I got it to work but not as what I intended.
When I run the code it scans my text file I inputted and only output one of the words in the text file that match the array in my code. When I add other words to the text file that is in the array it gives me a error.
And can someone please help me change it so it more in c++ code?
This is what I want to look like:
And this is what I get:
#include <fstream>
#include <iostream>
#include <cmath>
#include <iomanip>
#define SIZE 30
using namespace std;
const char *Phish[SIZE] ={"Amazon","official","bank","security",
"urgent","Alert","important","inform ation", "ebay", "password", "credit", "verify",
"confirm", "account","bill", "immediately", "address", "telephone","SSN", "charity",
"check", "secure", "personal", "confidential",
"ATM", "warning","fraud","Citibank","IRS", "paypal"};
int point[SIZE] = {2,2,1,1,1,1,2,2,3,3,3,1,1,1,1,1,2,2,3,2,1,1,1,1,2,2,2,2,2,1};
int totalPoints[SIZE];
void outputResults();
int main(void)
{
FILE *cPtr;
char filename[100];
char message[5000];
char *temp[100];
int i;
int counter=0;
int words=0;
char *tokenPtr;
cout << "Enter the name of the file to be read: \n";
cin >> filename;
if ( (cPtr = fopen(filename,"rb")) == NULL)
{
cout <<"File cannot be opened.\n";
}
else
{
fgets(message, 5000, cPtr);
tokenPtr = strtok(message, " ");
temp[0] = tokenPtr;
while (tokenPtr!=NULL)
{
for(i=0; i< SIZE; i++)
{
if(strncmp(temp[0], Phish[i], strlen(Phish[i]))==0)
{
totalPoints[i]++;
break;
}
tokenPtr =strtok(NULL, " ");
temp[0] = tokenPtr;
words++;
}
outputResults();
cout << "\n";
return 0;
}
}
}
void outputResults()
{
int i;
int count =0;
int a;
cout<<left<<setw(5) << "WORD "
<< setw(7)<<"# OF OCCURRENCE "
<< setw(15)<<"POINT TOTAL";
for(i=0; i<SIZE; i++)
{
if(totalPoints[i] !=0)
{
cout<<"\n"<<left << setw(10)<< Phish[i]
<< setw(11)<< totalPoints[i]
<< setw(13)<< point[i]*totalPoints[i];
count += point[i] * totalPoints[i];
}
}
cout<< "\nPoint total for entire file: \n"<< count;
}
First, your for loop is not written correctly. What you want to do is take a word from the file, and search your phishing array for that word. Right now, you are going through your phishing array without starting at the beginning of this array when you get a word.
Instead you should be taking a word, and then loop through the phishing array to see if the word exists. If it's not found, then get the next word, check if it's in the array starting from the beginning, etc.
fgets(message, 5000, cPtr);
tokenPtr = strtok(message, " ");
while (tokenPtr != NULL)
{
// start the search in the array
for (i = 0; i < SIZE; i++)
{
if (strncmp(tokenPtr, Phish[i], strlen(Phish[i])) == 0)
{
totalPoints[i]++;
break;
}
}
// get the next word in the file
tokenPtr = strtok(NULL, " ");
words++;
}
outputResults();
You also don't need temp[0] at all in the program. Just use tokenPtr.

Can't solve floating point exception in c++

This is my code.
#include <iostream>
using namespace std;
typedef struct
{
int polski;
int wf;
int matma;
}oceny;
int funkcja_liczaca(int suma, int ile_liczb, int ktory_przedmiot, oceny &temporary);
int main()
{
int suma = 0;
int temp[3];
int ile_liczb_zostalo_wprowadzonych = 0;
oceny database;
string teksty[3] = {"polski: ", "wf: ", "matma: "};
for (int i=0; i!=3; i++)
{
cout << teksty[i] << endl;
while(temp[i]!=0)
{
cin >> temp[i];
if(cin.good()) //floating point exception here. the code don't even step into this one.
{
{
suma = temp[i] + suma;
ile_liczb_zostalo_wprowadzonych++;
if(temp[i]==0){ile_liczb_zostalo_wprowadzonych--;}
}
}else cout << "error";
};
funkcja_liczaca(suma, ile_liczb_zostalo_wprowadzonych, i, database);
suma = 0;
ile_liczb_zostalo_wprowadzonych = 0;
}
cout << "output of struct members in main() \n";
cout << database.polski << endl;
cout << database.wf << endl;
cout << database.matma << endl;
return 0;
}
int funkcja_liczaca(int suma, int ile_liczb, int ktory_przedmiot, oceny &temporary)
{
if(ktory_przedmiot==0){temporary.polski=suma/ile_liczb;cout << temporary.polski << endl;}
if(ktory_przedmiot==1){temporary.wf=suma/ile_liczb;cout << temporary.wf << endl;}
if(ktory_przedmiot==2){temporary.matma=suma/ile_liczb;cout << temporary.matma << endl;}
}
It counts arithmetic average of inputed numbers untill user input 0 which ends loop. then the arithmetic average of thoose numbers is counted in the funkcja_liczaca() and it's saved into the members of struct oceny.
everything works fine but i want to implement something like "stream" check while inputing from keyboard to prevent inputing bad variables into integer type variable.
so inputing 'g' into temp[i] is causing floating point exception. the question is why? cin.good() and cin.fail() is not working.
When you want to deal with errors in the input stream, it's better to read the input line by line as a string and then attempt to extract your data from the string. If extraction of the data from the string is successful, proceed to process the data. Otherwise, attempt to read the next line of text. Here's the core logic for that.
while ( true )
{
cout << teksty[i] << endl;
std::string line;
if ( !getline(cin, line) )
{
// Problem reading a line of text.
// Exit.
exit(EXIT_FAILURE);
}
// Construct a istringstream object to extract the data.
std::istringstream istr(line);
if ( istr >> temp[i] )
{
// Extracting the number was successful.
// Add any additional checks as necessary.
// Break out of the while loop.
break.
}
// Bad input. Continue to the next iteration of the loop
// and read the next line of text.
}

Encrypting a string with a stack

I received an assignment for my C++ class last week. I think some of you will find it interesting! I managed to get most of the code down but I'm stuck and cannot figure this out for the life of me... Below are the guidelines for the encrypting process I must put into code:
The message sender inputs a four letter word, CCCC, and another four letter word,
XXXX.
The message sender then inputs the message to be encrypted.
The program scans the message one char at a time and each char is pushed in a stack until
either the scanned character is in the word CCCC or the end of the message is
encountered.
When the scanned character is one of the chars in CCCC, print that char and continue
to print and pop the chars at the top of the stack until either the stack is empty or the
char at the top of the stack is one of the chars in XXXX. When the end of the
message is encountered, print the character at the top of the stack and continue to pop
and print from the top of the stack until the stack is empty.
Here is a hint: "GOOD" "LUCK", it "SOUNDS SIMPLE TO ME", or as
your program would say: "OSDNOT EEM LPMIS SU"
So that is the actual assignment.
What I am having trouble with is the last bit:
When the end of the
message is encountered, print the character at the top of the stack and continue to pop
and print from the top of the stack until the stack is empty.
now here is the code I have so far:
#include <string>
#include <iostream>
using namespace std;
class Stack
{
private:
char Chars[50];
int top;
public:
int push(char);
char pop();
bool isEmpty();
bool isFull();
Stack()
{
top = 0;
}
};
int main()
{
Stack theStack;
char word1[4];
char word2[4];
for(int i=0; i < 4; i++){
word1[i] = ' ';
word2[i] = ' ';
}
char message[500];
cout << "Please enter a 4 letter word: ";
cin >> word1;
while(word1[4] || !word1[3])
{
cout << "Word must be 4 chars long. Try again: ";
cin >> word1;
}
cout << "Please enter another 4 letter word: ";
cin >> word2;
while(word2[4] || !word2[3])
{
cout << "Word must be 4 chars long. Try again: ";
cin >> word2;
}
cout << "Please enter the phrase to be encrypted (50 chars max): ";
cin.ignore(1000, '\n');
cin.getline(message,500);
int length = strlen(message);
int count = 0;
char finalMsg[length];
//scanner
for(int i = 0; i < length; i++)
{
if(message[i] == word1[0] ||
message[i] == word1[1] ||
message[i] == word1[2] ||
message[i] == word1[3])
{
finalMsg[count] = message[i];
count++;
if(message[i-1] != word2[0] ||
message[i-1] != word2[1] ||
message[i-1] != word2[2] ||
message[i-1] != word2[3])
{
finalMsg[count] = message[i-1];
count++;
}
}
else
{
theStack.push(message[i]);
}
}
cout << finalMsg << endl;
return 0;
}
int Stack::push(char data)
{
Chars[top] = data;
top++;
return top;
}
char Stack::pop()
{
char ret = Chars[top-1];
top--;
return ret;
}
bool Stack::isEmpty()
{
if(top <= 0)
return true;
else return false;
}
bool Stack::isFull()
{
if(top >= 50)
return true;
else return false;
}
When compiled, the final output gives me "OSDNOT" which is in the example provided by my professor, so I know I'm heading down the right track.. Any help would be great, I don't even know where to begin to examine the code.
Here is the corrected code. You didn't code the algorithm right. I have commented the changes i have made in the code.
first of all, you didn't pop out the elements of the stack when you encountered a character present in CCCC while scanning. Also at the end of scanning, you didn't empty the stack. Include cstring instead of string. As pointed out in the comments, your declaration for word1 and word2 is incorrect.
char finalMsg[200];
//scanner
for(int i = 0; i < length; i++)
{
if(message[i] == word1[0] ||
message[i] == word1[1] ||
message[i] == word1[2] ||
message[i] == word1[3])
{
finalMsg[count] = message[i];
count++;
//pop out elements from the stack till it is empty or an character of XXXX is encountered
while(!theStack.isEmpty())
{
char tmp=theStack.pop();
if(tmp==word2[0] ||
tmp==word2[1] ||
tmp==word2[2] ||
tmp==word2[3])
{
theStack.push(tmp);
break;
}
finalMsg[count++]=tmp;
}
}
else
{
theStack.push(message[i]);
}
}
//empty the stack
while(!theStack.isEmpty())
{
finalMsg[count++]=theStack.pop();
}
finalMsg[count++]=0;
cout << finalMsg << endl;
PS: Better use std::stack and std::string.

C++ Novice regarding Vectors and for/while loops

I’m trying to make something that will take lines of input from the user, separate them into strings in a vector, then print them one at a time (8 per line).
so far this is what I’ve got:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
int main(void)
{
using namespace std;
vector<string> svec1;
string temp;
while(getline(cin, temp)) //stores lines of text in temp
{
if(temp.empty()) //checks if temp is empty, exits loop if so.
break;
stringstream ss(temp);
string word;
while(ss >> word) //takes each word and stores it in a slot on the vector svec1
{
svec1.push_back(word);
}
}
}
I’m stuck on getting it to print them 8 at a time, the solutions I’ve tried keep getting subscript out of range errors.
Something like this:
for(int i = 0; i < svec1.size(); i++)
{
cout << svec1[i];
if ((i+1) % 8 == 0)
cout << endl;
else
cout << " ";
}
?
EDIT:
the solution above outputs extra space/newline at the end. It can be avoided by something like this:
for(int i = 0; i < svec1.size(); i++)
{
if (i == 0)
/*do nothing or output something at the beginning*/;
else if (i % 8 == 0)
cout << endl; /*separator between lines*/
else
cout << " "; /*separator between words in line*/
cout << svec1[i];
}
Walk over your vector with an index:
for (unsigned int idx = 0; idx < svec1.size(); ++idx) {
std::cout << svec[idx] << sep(idx); // sep(idx) is conceptual; described below
}
What is this sep(idx)? It is the separator to print after the idxth word. This is
A newline after having printed eight words on a line. idx will be 7, 15, 23, etc: One shy of an integer multiple of 8. In code, (idx+1)%8 == 0.
A newline for the last item in the vector; you probably want the last item to be followed with a newline. In code idx+1 == svec.size().
A space otherwise.
An easy way to do this is with the ternary operator:
for (unsigned int idx = 0; idx < svec1.size(); ++idx) {
const char * sep = (((idx+1)%8 == 0) || (idx+1 == svec.size())) ? "\n" : " ";
std::cout << svec[idx] << sep;
}
If you don't like that,
for (unsigned int idx = 0; idx < svec1.size(); ++idx) {
const char * sep;
if (((idx+1)%8 == 0) || (idx+1 == svec.size())) {
sep = "\n";
}
else {
sep = " ";
}
std::cout << svec[idx] << sep;
}
Normally you iterate over a vector using a for loop clause. So if you want to print all elements of your vector<string> you have to make something like this:
for(vector<string>::iterator it = myvec.begin(); it != myvec.end(); ++it) {
cout << *it;
}
EDIT: as Vlad has posted correctly, you can also use array indices, which are less efficient in lists, but equally efficient with vectors.