This is a basic program to get two 5-digit numbers as string and use addition on the 2 numbers utilising operator overloading on '+' .
#include <iostream>
#include <limits>
#include <cstdlib>
#include <cstring>
#include <sstream>
using namespace std;
class IntStr
{
int InputNum;
public:
//IntStr();
IntStr::IntStr(int num);
IntStr operator+ (const IntStr &);
//~IntStr();
void Display();
};
IntStr::IntStr(int num)
{
InputNum = num;
}
void IntStr::Display()
{
cout << "Number is (via Display) : " << InputNum <<endl;
}
IntStr IntStr::operator+ (const IntStr & second) {
int add_result = InputNum + second.InputNum;
return IntStr(add_result);
}
int main()
{
string str;
bool option = true;
bool option2 = true;
while (option)
{
cout << "Enter the number : " ;
if (!getline(cin, str))
{
cerr << "Something went seriously wrong...\n";
}
istringstream iss(str);
int i;
iss >> i; // Extract an integer value from the stream that wraps str
if (!iss)
{
// Extraction failed (or a more serious problem like EOF reached)
cerr << "Enter a number dammit!\n";
}
else if (i < 10000 || i > 99999)
{
cerr << "Out of range!\n";
}
else
{
// Process i
//cout << "Stream is: " << iss << endl; //For debugging purposesc only
cout << "Number is : " << i << endl;
option = false;
IntStr obj1 = IntStr(i);
obj1.Display();
}
}//while
while (option2)
{
cout << "Enter the second number : " ;
if (!getline(cin, str))
{
cerr << "Something went seriously wrong...\n";
}
istringstream iss(str);
int i;
iss >> i; // Extract an integer value from the stream that wraps str
if (!iss) //------------------------------------------> (i)
{
// Extraction failed (or a more serious problem like EOF reached)
cerr << "Enter a number dammit!\n";
}
else if (i < 10000 || i > 99999)
{
cerr << "Out of range!\n";
}
else
{
// Process i
//cout << "Stream is: " << iss << endl; //For debugging purposes only
cout << "Number is : " << i << endl;
option2 = false;
IntStr obj2 = IntStr(i);
obj2.Display();
//obj1->Display();
}
}//while
//IntStr Result = obj1 + obj2; // --------------------> (ii)
//Result.Display();
cin.get();
}
Need clarification on the points (i) & (ii) in the above code ...
(1) What does (i) actually do ?
(2) (ii) -> Does not compile.. as the error "obj1 not declared (first use this function)" comes up. Is this because obj1 & obj2 are declared only inside the while loops? How do I access them globally?
1) From http://www.cplusplus.com/reference/iostream/ios/operatornot/ :
bool operator ! ( ) const; Evaluate
stream object
Returns true if either one of the
error flags (failbit or badbit) is set
on the stream. Otherwise it returns
false.
From http://www.cplusplus.com/reference/iostream/ios/fail/ :
failbit is generally set by an input
operation when the error was related
with the internal logic of the
operation itself, while badbit is
generally set when the error involves
the loss of integrity of the stream,
which is likely to persist even if a
different operation is performed on
the stream.
2) The two objects are not in scope, they exists only in the previous brackets.
calls the overloaded operator which evaluates the stream in boolean context. This checks the state of the stream to see if the previous operation had failed - if so, you cannot rely on the value in the integer variable i being valid because the input on the stream was not an integer.
the variables obj1 and obj2 are defined in the scope of the while loop - they are not available outside the scope. You can declare them outside the scope of the while in which case the variable will hold the last value it held in the while loop.
if (!iss)
tests if the stream is in a bad state, which will be the case if a conversion failed or if you are at the end of the stream
obj1 is defined here:
else
{
// Process i
//cout << "Stream is: " << iss << endl; //For debugging purposesc only
cout << "Number is : " << i << endl;
option = false;
IntStr obj1 = IntStr(i);
obj1.Display();
}
it is therefore local to the else-block & can't be accessed outside it. If you want to increase its scope, modve its definition outside of the block. It is not a good idea to move it outside of all blocks (i.e. make it global), however.
Related
std::count returns a value and I need this value to reset to 0 for all characters in the variable 'counter' after executing the inner for loop. Goal is to count how many times a character appears. If this character appears twice in the string, add one to variable 'd'. If it appears three times, add one to variable 'e'.
Not sure what else to try or if there is potentially a better function to achieve my result.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstring>
int main() {
std::string data;
std::vector<std::string> myString;
std::vector<char> myChar;
int d = 0, e = 0;
std::ifstream inFile;
inFile.open("C:\\Users\\Administrator\\Desktop\\c++ files\\input2.txt");
if (!inFile) {
std::cout << "oops";
}
for (int i = 0; i < 1; i++) {
inFile >> data;
std::copy(data.begin(), data.end(), std::back_inserter(myChar)); //copy from string data to vector myChar via back inserter.
char counter = 'a';
for (int i = 0; i < 26; i++) {
int myCount = std::count(myChar.begin(), myChar.end(), counter);
if (myCount == 2) {
d++;
}
else if (myCount == 3) {
e++;
}
std::cout << "Counter : " << counter << " myCount : " << myCount << "\n";
counter++;
}
}
std::cout << "d is: " << d << "\n";
std::cout << "e is: " << e << "\n";
return 0;
}
input file -- https://adventofcode.com/2018/day/2
The program works correctly on first inner for loop, but second and after return values that are too high (albeit correct) for the 'myCount' variable.
std::count doesn't just give you a random value, it gives you a specific value based on the contents of the range you give it. You can't change that behaviour, not should you want to.
Instead, look at that range. Why does std::count gives values that you don't expect? They are either "too high" or they are "correct" and cannot be both; fortunately they are the latter.
This is because you repeatedly std::back_insert to the vector inside your loop. As the loop progresses, you keep counting the old characters from the last time!
If you first cleared myChar then you wouldn't have the problem. Or, ideally, bring the declaration of myChar inside the loop.
A few fixes
1) On error the program should end, not continue:
if (!inFile)
{
std::cout << "oops";
return 1;
}
2) a)myChar is accumulating all the chars of all previously read words, so it has to be cleared before use with every pass of the loop, best to move it's declaration into the block required;
b) if you're using a counter just to count but not using it, better to iterate over the data - in this case get rid of i and iterate with chars checked_char:
while (inFile >> data)
{
std::vector< char > myChar;
std::copy(data.begin(),
data.end(),
std::back_inserter(myChar)); //copy from string data to vector myChar via back inserter.
for (char checked_char = 'a'; checked_char <= 'z'; ++checked_char)
{
int myCount = std::count(myChar.begin(), myChar.end(), checked_char);
if (myCount == 2)
{
d++;
}
else if (myCount == 3)
{
e++;
}
std::cout << "Counter : " << checked_char << " myCount : " << myCount << "\n";
}
}
I'm having a little trouble with my code. It's pretty much supposed to open two files, and compare the first twenty line of the file "StudentAnswers.txt" [inputted as a char into a char array] against a char value in (each line of another file) "CorrectAnswers.txt" in another array at the same position (index). It's like a linear search, but the same position in the arrays. Then a report should be displayed, detailing which question the student missed, the given answer, the correct answer, and if the student passed (got >= 70%) or not, like the following:
Report for Student X:
2 (A/D), 3 (C/D), 5(D/A)
This student passed the exam!
Then it should clear the SAArray, and feed the next twenty lines from StudentAnswers.txt, and start the process all over again. I guess the program has to determine the number of students from (lines of 'StudentAnswers.txt' file / 20).
I'm having trouble displaying the report, and having the array clear itself after the program. I'm guessing this can be done with a while loop and an accumulator for the number of students (to be determined by above equation).
Also, Visual Studio seems to go to "Missed __ questions for a total of ___ %", and then keep looping -858993460.
Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
void GradeReturn(char[], char[], int, int, int);
string PassFail(float);
int main()
{
ifstream SA("StudentAnswers.txt");
ifstream CA("CorrectAnswers.txt");char CAArray[20];
char SAArray[20];
// char SA2Array[20];
bool isCorrect;
int correct;
int incorrect;
int counter;
correct = 0;incorrect = 0;
counter = 0;
cout << endl;
if (!SA.fail())
{
cout << "'StudentAnswers.txt' file opened successfully." << endl;
cout << "'CorrectAnswers.txt' file opened successfully." << endl << endl;
int a = 0;
int b = 0;
while (a < 20)
{
CA >> CAArray[a];
a++;
} // while loop to feed char into the array
while (b < 20)
{
SA >> SAArray[b];
b++;
}
} // while loop to feed char into array
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
return 0;
}
void GradeReturn(char CAArray[], char SAArray[], int correct, int incorrect, int counter)
{
float percent;
float hundred;
int student;
int catcher[20];
int writeCatcher; int starter;
int catcher_size;
student = 0;
writeCatcher = 0;
catcher_size = ((sizeof catcher) / 4);
while (counter < 20)
{
if ((CAArray[counter]) == (SAArray[counter]))
{
correct++;
cout << "Good job!" << endl;
} // correct handling
else
{
incorrect++;
cout << "You got question " << counter << " wrong." << endl;
counter >> catcher[writeCatcher];
writeCatcher++;
} // incorrect handling
counter++;
} // while loop to determine if a student got a question right or wrong
static_cast <float> (incorrect); // float conversion
cout << endl; // for cleanliness
percent = ((static_cast <float> (correct)) / 20); // percentage
hundred = percent * 100;
PassFail(percent);
if (PassFail(percent) == "pass")
{
student++;
cout << "Report for Student " << student << ":" << endl;
cout << "-----------------------------" << endl;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
starter = 0;
while (starter < (sizeof catcher)
{
if(1=1)
{
catcher_size
}
else
{
cout << "";
starter++;
}
}
}
else if (PassFail(percent) == "fail")
{
student++;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
while (starter < catcher_size)
{
if ((catcher[starter]) == -858993460)
{
starter++;
}
else
{
cout << "";
starter++;
}
}
}
return;
}
string PassFail(float percent)
{
if (percent >= 0.70) // if <pass>
{
return "pass";
}
else // if <fail>
{
return "fail";
}
cout << endl;
}
To get a loop you should keep streams open instead of closing them after reading 20 lines.
As pseudo code that would be:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
a = 0; // Reset a
}
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
You would also need to pass correct, incorrect, counter by reference so that the GradeReturn can change their value and their by do the accumulation.
Like:
void GradeReturn(char CAArray[], char SAArray[], int& correct, int& incorrect, int& counter)
Further you shouldn't rely on being able to read exactly Nx20 lines from the files every time. A file could have, e.g. 108 (5x20 + 8) lines, so you code should be able to handle the with only 8 lines. In other words, don't hard code 20 in your function like while (counter < 20). Instead pass the number of lines to be handled and do while (counter < number_to_handle).
Something like this as pseudo code:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
// ^
a = 0; // Reset a
}
}
if (a != 0)
{
// Process the rest
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
One problem you have is you're trying to compare C-style strings with the == operator. This will compare them essentially as if they were pointers to char, i.e. compare whether they point at the same location in memory, not compare the contents of the string. I urge you to look up array-decay and c-string variables to understand more.
Specifically, if (PassFail(percent) == "pass") isn't going to do what you want it to. strcomp doc, strncmp doc using std::string variables instead of c-style strings would all work, but it would be better simply to compare percent to a value, i.e. if(percent >= 0.70 directly instead of calling PassFail and comparing a string.
There are many other issues here also, you at one point call PassFail but do nothing with the return value. The only side affect of PassFail is cout << endl, if that's what you intend, it's a poor decision and hard to read way to put a newline on the console.
Try asking your compiler for more warnings, that's often helpful in finding these types of issues. -Wall -Wextra work for gcc, you may have to read your compiler manual...
I am having a hard time parsing an edge list from a text file in c++. The edge list is in the following format:
*Edgeslist
1 6487
2 6488 6489 6490 6491 6492 6493 6494 6495 6496
3 6497 6498 6499 6500 6501 6502 6503 6504 6505
4 6506 6507 6508
5 6509 6510 6511
6 6512 6513 6514 6515
7 6516
8 6517 6518
9 6519 6520
10 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535
11 6566
My vector is a vector of structs that is defined here
struct Edge{
int character;
int edges[16];
};
The first number of each line should be read into the character integer and the rest should be read into the edges array. I have tried a few for loops, and currently working on a lengthy while loop with if statements for each number of possible integers to go into the array (max of 15 integers per line after the first number). Here is a part of my implementation so you can see what I am attempting.
while(std::getline(input, line))
{
int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o;
std::stringstream ss(line);
if ( ss >> a)
{
std::cout << "1 " << a << "\n";
}
if ( ss >> a >> b)
{
std::cout << "2 " << a << " " << b << "\n";
}
if ( ss >> a >> b >> c)
{
std::cout << "3 " << a << " " << b << " " << c << "\n";
}
if ( ss >> a >> b >> c >> d)
{
std::cout << "4 " << a << " " << b << " " << c << " " << d << "\n";
}
I'll end it there but it does go on for awhile until it covers every possible line.
At the moment I am just trying to figure out the basic logic to parse this text file.
You have tagged this as C++.
I would recommend you add an initializer if you must continue with pod ...
struct Edge
{
int character;
int edges[16];
// more data attributes
// use ctor to initialize these values
Edge(void) :
character (0)
// edges[16]
{
for (int i=0; i<16; ++i)
edges[i] = 0;
}
// use dtor to clear them
~Edge(void)
{
for (int i=0; i<16; ++i)
edges[i] = 0;
character = 0;
// ...
}
};
I suspect you will also need a count of how many edges have currently been in installed (or perhaps call it nextIn).
The fundamentally important signature of C++ code is the preferred use of objects-defined-by-a-class. I recommend you consider:
struct Edge
{
int character; // poor name choice
std::vector<int> edges; // << use vector, not array
// use ctor to initialize these values
Edge(void) :
character (0)
// edges // default ctor does what you need
{
}
~Edge(void) {
// edges default dtor does what you need
character = 0;
}
};
The std::vector reduces your work to read arbitrary counts of values.
// Typical input:
// 3 6497 6498 6499 6500 6501 6502 6503 6504 6505
// 4 6506 6507 6508
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
struct Edge
{
int character; // <<< poor name choice
std::vector<int> edges; // <<< use vector, not array
// use ctor to initialize these values
Edge(void) :
character (0)
// edges default ctor does what you need
{
}
~Edge(void) {
// edges default dtor does what you need
character = 0;
}
bool ok(void) {
/*tbd - count errors? size check? */
return(true);
};
void load(std::string line)
{
// typical input line
// 3 6497 6498 6499 6500 6501 6502 6503 6504 6505
// 4 6506 6507 6508
std::stringstream ss(line+' ');
// padding at end ---------^----because ss.eof() sooner than I expected
//debug only
//std::cout << " in: (" << std::setw(3) << line.size() << ")
// << line << std::endl;
// process one work buff
do {
ss >> character; // read 1st int of line
if (ss.eof()) break;
if (ss.bad()) {
// maybe invalid integer format
std::cerr << "bad input: " << line << std::endl;
// tbd - error count?
break;
}
// process 1 or more entries for edge.vector from line
do {
int edgeVal = 0;
ss >> edgeVal;
if (ss.eof()) break;
if (ss.bad()) {
// maybe invalid integer format
std::cerr << "bad input: " << line << std::endl;
// tbd - error count?
break;
}
// additional edgeVal validations?
edges.push_back(edgeVal); // fill in one value to edge vector
// add validation here if edges.size() has an upper limit
// tbd - error count?
} while (1); // // process 1 or more entries to vector from line
} while(1); // one work buff
// debug only
dump();
} // void load(std::stringstream& ss, std::string line)
// for debug
void dump()
{
std::cout << "dump: (" << std::setw(3) << edges.size()
<< ") " << character << " ";
for (size_t i=0; i<edges.size(); ++i)
std::cout << edges[i] << " ";
std::cout << std::endl;
}
}; // struct Edge()
int t237(void)
{
std::vector<Edge> edgeVec;
// file processing at outer scope
do {
std::string line; // work buff
(void)std::getline(std::cin, line);
if(std::cin.eof()) break;
std::stringstream ss(line);
Edge temp; // a work buff
temp.load(line); // <<< load method for Edge (part of Edge)
// not sure where to put all the Edge objects
// temporarily, use edgeVec;
if (temp.ok()) // add flag check that edgeVec had no errors
edgeVec.push_back(temp);
else
/*tbd*/{}; // error in temp ... discard it? report it?
} while (1);
// tbd - how return vector and file status
return (0);
}
---- update
ss.eof() occurring before I expected ... added "padding at end"
added dump() debug method, added debug cout of input line
minimal testing complete
You should split your string into substrings at whitespaces. Details are explained here.
After that, you just cast your substrings to appropiate type.
std::stringstream ss(line);
ss >> character;
unsigned int n=0;
while(ss >> edges[n])
{
++n;
}
(One could make this a little shorter, but that would make it less readable.)
I searched a lot on google and stackoverflow but I couldn't find my answer. I'm actually reading a C++ book (C++ Primer 5th Edition) and they're asking me to do an exercise.
"Write a program that reads several transactions and counts how many transactions occur for each ISBN" (Console Project)
This is my code atm :
Sales_item currentItem, item;
if (cin >> currentItem)
{
int cnt = 1;
while (cin >> item)
{
if (currentItem.isbn() == item.isbn())
{
++cnt;
}
else
{
cout << currentItem.isbn() << " occurs " << cnt << " times " << endl;
cnt = 1;
currentItem = item;
}
}
cout << item.isbn() << " occurs " << cnt << " times " << endl;
}
I won't explain how work the transactions so I'm gonna ask it in another way.
I type in my console 6(or more) random strings as exemple:
101A
102A
101A
101A
103A
102A
I want the result the result (output) to be:
101A occurs 3 times.
102A occurs 2 times.
103A occurs 1 times.
How would you do that?
Using std::map instead of list will be easier.
int main()
{
map<string,int> stringMap;
for (int i=0;i<3;i++)
{
cout<<"Enter string: ";
string s;
cin>>s;
if(stringMap.find(s)!=stringMap.end())
{
stringMap[s]++;
}
else
{
stringMap[s]=1;
}
}
for (map<string,int>::const_iterator itr = stringMap.cbegin(); itr!=stringMap.cend(); ++itr)
{
if(itr->second > 1)
cout<<itr->first << " occurs "<<itr->second<<" times"<<endl;
else
cout<<itr->first << " occurs "<<itr->second<<" time"<<endl;
}
return 0;
}
There are multiple approaches to a question like this, so the best would depend on your constraints. My approach would be:
while(GetInputString(str)) {
myStruct* ptr = existingList.Find(str);
if (!ptr) {
existingList.Add(str);
} else {
ptr->IncrementCount();
}
}
I've tried not to solve your problem for you - hopefully the answer gives you a template to work with...
#include <iostream>
#include <vector>
#include "Sales_item.h"
using namespace std;
void book_transactions(string isbn, int count);
int main()
{
vector<Sales_item> book_vec;
Sales_item book;
int total_transactions = 1;
// Reads in Sales_item objects
while (cin >> book)
{
book_vec.push_back(book);
}
// Compares ISBNs in vector, if two isbns are equal total transactions increases
for (int i = 0; i < book_vec.size() - 1; i++)
{
if (book_vec[i].isbn() == book_vec[i+1].isbn())
{
total_transactions = book_vec[i].get_units_sold() + book_vec[i+1].get_units_sold();
book_transactions(book_vec[i].isbn(), total_transactions);
}
}
}
void book_transactions(string isbn, int count)
{
cout << "ISBN: " << isbn << " " << "Transactions: " << count << endl;
}
I went into the Sales_item.h class and added a method to get the number of units sold. There was already a class member (unsigned return type) under private. I just created a getter and then created a vector of Sales_items. This solution seems to work. I'm sure the intended problem is not for an N set of sales_items, however this should work as a "duct-tape" solution. There is no need to play around with pointers at this point. A simple vector array and an algorithm to compare adjacent objects works just fine.
I'm trying to make a program that looks for syntax and everytime it goes from state to state
It needs to indicate that state. I'm getting different output that I shouldn't have got.
using namespace cppfsm;
#include <vector>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int cppfsm::updateState(int& state, char c) {
const int state1 = 1;
const int state2 = 2;
switch (state) {
case state1:
if (c == '/')
cout << "1" << endl;
// do stuff; update state
else if (c == '"')
cout << "1" << endl;
// do something else; update state
case state2:
if (c == '/')
cout << "1" << endl;
// do stuff; update state
else if (c == '"')
cout << "1" << endl;
// do something else; update state
}
return 0;
}
void testFSM(string s) {
vector<int> stlist; // list of states.
int cstate = start;
for (unsigned long i = 0; i < s.length(); i++) {
stlist.push_back(updateState(cstate,s[i]));
}
// push the last state:
stlist.push_back(cstate);
cout << s << endl;
for (unsigned long i = 0; i < stlist.size(); i++) {
cout << stlist[i];
}
cout << endl;
}
int main() {
// the finite state machine:
string input;
while(getline(cin,input)) {
cout << " ";
testFSM(input);
}
return 0;
}
the output should be looking like this.
the numbers are the states when going from 1 to another
$ echo "int x; // holds stuff" | ./fsm
int x; // holds stuff
0111010042222222222222
$ echo 'cout << "some string";' | ./fsm
cout << "some string";
01111000033333333333300
$ echo 'cout << "\"escape\" chars are fun";' | ./fsm
cout << "\"escape\" chars are fun";
011110000353333333533333333333333300
But my output comes out to be all 0000......s. How do I fix this problem?
If you're wondering why stlist is all 0's, take a look at the return statement for updateState:
return 0;
}
Compare this with your code for populating stlist:
stlist.push_back(updateState(cstate,s[i]));
As far as I can tell, all 0's is the correct behavior of this code. Obviously, this is not the expected or logical behavior, so I suggest changing updateState:
int cppfsm::updateState(int& state, char c) {
// ...
return state;
}
Now when you run the code stlist should contain each state change as intended.
It looks like you aleays call updateState with the same value, start. That value ist not handled in the switch, so the function returns zero. This means tha you just keep appending zeros to the stlist vector.
Try handling the start state in the switch, and the return value of the updateState function should be assigned to the cstate variable.
Your code never checks you start state:
switch (state) {
case state1: /* ... */
case state2: /* ... */
case start : /* ... */
}